Додавання стовпця до фрейму data.frame


115

Я маю data.frame нижче. Я хочу додати стовпчик, який класифікує мої дані відповідно до стовпця 1 ( h_no) таким чином, що перша серія h_no 1,2,3,4 - клас 1, друга серія h_no(1 - 7) - клас 2 тощо. такі, як зазначено в останньому стовпці.

h_no  h_freq  h_freqsq
1     0.09091 0.008264628 1
2     0.00000 0.000000000 1
3     0.04545 0.002065702 1
4     0.00000 0.000000000 1  
1     0.13636 0.018594050 2
2     0.00000 0.000000000 2
3     0.00000 0.000000000 2
4     0.04545 0.002065702 2
5     0.31818 0.101238512 2
6     0.00000 0.000000000 2
7     0.50000 0.250000000 2 
1     0.13636 0.018594050 3 
2     0.09091 0.008264628 3
3     0.40909 0.167354628 3
4     0.04545 0.002065702 3

Відповіді:


155

Ви можете додати стовпчик до своїх даних, використовуючи різні методи. Котирування нижче приходять з розділу «Подробности» відповідного тексту довідки, [[.data.frame.

Кадри даних можна індексувати в декількох режимах. Коли [і [[використовуються з одним векторним індексом ( x[i]або x[[i]]), вони індексують кадр даних так, ніби це список.

my.dataframe["new.col"] <- a.vector
my.dataframe[["new.col"]] <- a.vector

Метод data.frame для $, трактується xяк список

my.dataframe$new.col <- a.vector

Коли [і [[використовуються з двома індексами ( x[i, j]і x[[i, j]]), вони діють як індексація матриці

my.dataframe[ , "new.col"] <- a.vector

Оскільки метод data.frameпередбачає, що якщо ви не вкажете, чи працюєте ви зі стовпцями чи рядками, він вважатиме, що ви маєте на увазі стовпці.


Для вашого прикладу це має працювати:

# make some fake data
your.df <- data.frame(no = c(1:4, 1:7, 1:5), h_freq = runif(16), h_freqsq = runif(16))

# find where one appears and 
from <- which(your.df$no == 1)
to <- c((from-1)[-1], nrow(your.df)) # up to which point the sequence runs

# generate a sequence (len) and based on its length, repeat a consecutive number len times
get.seq <- mapply(from, to, 1:length(from), FUN = function(x, y, z) {
            len <- length(seq(from = x[1], to = y[1]))
            return(rep(z, times = len))
         })

# when we unlist, we get a vector
your.df$group <- unlist(get.seq)
# and append it to your original data.frame. since this is
# designating a group, it makes sense to make it a factor
your.df$group <- as.factor(your.df$group)


   no     h_freq   h_freqsq group
1   1 0.40998238 0.06463876     1
2   2 0.98086928 0.33093795     1
3   3 0.28908651 0.74077119     1
4   4 0.10476768 0.56784786     1
5   1 0.75478995 0.60479945     2
6   2 0.26974011 0.95231761     2
7   3 0.53676266 0.74370154     2
8   4 0.99784066 0.37499294     2
9   5 0.89771767 0.83467805     2
10  6 0.05363139 0.32066178     2
11  7 0.71741529 0.84572717     2
12  1 0.10654430 0.32917711     3
13  2 0.41971959 0.87155514     3
14  3 0.32432646 0.65789294     3
15  4 0.77896780 0.27599187     3
16  5 0.06100008 0.55399326     3

Яка різниця між останніми двома методами додавання стовпця?
хун

2
@ huon-dbaupp метод із комою є явним і також працюватиме на матрицях, тоді як останній працює лише на data.frames. Якщо кома не передбачена, R передбачає, що ви маєте на увазі стовпці.
Роман Луштрик

12

Легко: ваш кадр даних - це A

b <- A[,1]
b <- b==1
b <- cumsum(b)

Тоді ви отримуєте стовпчик b.


Приємний і короткий. Я би просто змінив останній елемент, щоб замість того, cumsum(b) -> bщоб результат був безпосередньо доданий як стовпець до вихідного кадру даних, щось подібне A$groups <- cumsum(b).
A5C1D2H2I1M1N2O1R2T1

cumsum(b)дасть вам вектор довжиною 3, чи я щось пропускаю?
Роман Луштрик

@ RomanLuštrik, див. Рішення dbaupp, в якому пояснюється, як у цьому випадку буде працювати диплом.
A5C1D2H2I1M1N2O1R2T1

2
@ RomanLuštrik, це рішення можна переписати дуже красиво в один рядок. Використовуючи свої your.dfдані, ви можете просто зробити, your.df$group = cumsum(your.df[, 1]==1)щоб отримати новий груповий стовпець.
A5C1D2H2I1M1N2O1R2T1

7

Якщо я правильно розумію питання, ви хочете виявити, коли h_noвін не збільшується, а потім збільшується class. (Я збираюся ознайомитися з тим, як я вирішив цю проблему, в кінці є автономна функція.)

Робочий

h_noНа даний момент нас хвилює лише стовпець, тому ми можемо отримати це з кадру даних:

> h_no <- data$h_no

Ми хочемо виявити, коли h_noне йде вгору, що ми можемо зробити, працюючи, коли різниця між послідовними елементами або негативна, або нульова. R забезпечує diffфункцію, яка дає нам вектор відмінностей:

> d.h_no <- diff(h_no)
> d.h_no
 [1]  1  1  1 -3  1  1  1  1  1  1 -6  1  1  1

Після того, як ми це зробимо, знайти прості речі, які не є позитивними:

> nonpos <- d.h_no <= 0
> nonpos
 [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
[13] FALSE FALSE

В R, TRUEі FALSEв основному такі ж, як 1і0 , тому якщо ми отримаємо сукупну суму nonpos, вона збільшиться на 1 в (майже) відповідних плямах. cumsumФункція (яка в основному протилежність diff) може це зробити.

> cumsum(nonpos)
 [1] 0 0 0 1 1 1 1 1 1 1 2 2 2 2

Але є дві проблеми: цифри - одна занадто мала; і, нам не вистачає першого елемента (у першому класі повинно бути чотири).

Перша проблема просто вирішується: 1+cumsum(nonpos) . А другий просто вимагає додавання а 1до фронту вектора, оскільки перший елемент завжди в класі 1:

 > classes <- c(1, 1 + cumsum(nonpos))
 > classes
  [1] 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3

Тепер ми можемо прикріпити його назад до нашого кадру даних cbind (використовуючи class=синтаксис, ми можемо дати стовпцю classзаголовок):

 > data_w_classes <- cbind(data, class=classes)

А data_w_classesтепер містить результат.

Кінцевий результат

Ми можемо стиснути лінії разом і згорнути все це у функції, щоб полегшити їх використання:

classify <- function(data) {
   cbind(data, class=c(1, 1 + cumsum(diff(data$h_no) <= 0)))
}

Або, оскільки це має сенс для class бути фактором:

classify <- function(data) {
   cbind(data, class=factor(c(1, 1 + cumsum(diff(data$h_no) <= 0))))
}

Ви використовуєте будь-яку функцію, як:

> classified <- classify(data) # doesn't overwrite data
> data <- classify(data) # data now has the "class" column

(Цей спосіб вирішення цієї проблеми хороший тим, що дозволяє уникнути явної ітерації, що, як правило, рекомендується для R, і уникає генерації безлічі проміжних векторів та списку тощо. А також це якось добре, як це можна записати в одному рядку :))


2

Окрім відповіді Романа, щось подібне може бути ще простішим. Зауважте, що я не перевіряв його, оскільки зараз не маю доступу до R.

# Note that I use a global variable here
# normally not advisable, but I liked the
# use here to make the code shorter
index <<- 0
new_column = sapply(df$h_no, function(x) {
  if(x == 1) index = index + 1
  return(index)
})

Функція повторює значення в n_hoі завжди повертає категорії, до яких належить поточне значення. Якщо значення 1виявлено, ми збільшуємо глобальну змінну indexі продовжуємо.


Мені подобається зламати з глобальною змінною. Так Кіш. : P
Роман Луштрик

2

Я вважаю, що використання "cbind" - це найпростіший спосіб додати стовпчик до кадру даних у Р. Нижче прикладу:

    myDf = data.frame(index=seq(1,10,1), Val=seq(1,10,1))
    newCol= seq(2,20,2)
    myDf = cbind(myDf,newCol)


0

Підхід, заснований на визначенні кількості груп ( xin mapply) та його довжини ( yin mapply)

mytb<-read.table(text="h_no  h_freq  h_freqsq group
1     0.09091 0.008264628 1
2     0.00000 0.000000000 1
3     0.04545 0.002065702 1
4     0.00000 0.000000000 1  
1     0.13636 0.018594050 2
2     0.00000 0.000000000 2
3     0.00000 0.000000000 2
4     0.04545 0.002065702 2
5     0.31818 0.101238512 2
6     0.00000 0.000000000 2
7     0.50000 0.250000000 2 
1     0.13636 0.018594050 3 
2     0.09091 0.008264628 3
3     0.40909 0.167354628 3
4     0.04545 0.002065702 3", header=T, stringsAsFactors=F)
mytb$group<-NULL

positionsof1s<-grep(1,mytb$h_no)

mytb$newgroup<-unlist(mapply(function(x,y) 
  rep(x,y),                      # repeat x number y times
  x= 1:length(positionsof1s),    # x is 1 to number of nth group = g1:g3
  y= c( diff(positionsof1s),     # y is number of repeats of groups g1 to penultimate (g2) = 4, 7
        nrow(mytb)-              # this line and the following gives number of repeat for last group (g3)
          (positionsof1s[length(positionsof1s )]-1 )  # number of rows - position of penultimate group (g2) 
      ) ) )
mytb
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.