умножить каждую ячейку data.frame на его вес - PullRequest
8 голосов
/ 23 февраля 2011

Что я хочу сделать, так это смущать просто - тем не менее, я терплю неудачу.

У меня есть data.frame с "символами" и "цифрами". Один из столбцов data.frame представляет веса.

Я хочу умножить каждую ячейку фрейма данных на соответствующий вес (если это число).

Как мне это сделать (лучше всего без использования вложенного цикла).

Заранее спасибо!

Пример:

   c1   c2   w   
l1 abc  2    1
l2 dxf  3    0.5
l3 ghi  4    1.5

должно стать

   c1   c2   w   
l1 abc  2    1
l2 dxf  1.5  0.5
l3 ghi  6    1.5

Ответы [ 4 ]

6 голосов
/ 23 февраля 2011

Для воспроизводимого примера, dd - это фрейм данных со смесью типов переменных, где W - это веса.

dd <- data.frame(G=gl(2,2), X=rnorm(4), Y=1L:4L, Z=letters[1:4], W=0.3:3.3)
num.vars <- names(dd)[sapply(dd, is.numeric)]  #select numeric variables
num.vars <- setdiff(num.vars, "W")  # remove the weight variable
dd[num.vars] <- dd[num.vars] * dd$W  # multiply
5 голосов
/ 23 февраля 2011

Векторизация!

> dat <- data.frame(c1 = c("abc","dxf","ghi"), c2 = 2:4, w = c(1,0.5,1.5))

Эффективно, вы хотите c2 * w, но нам нужно указать R посмотреть внутри фрейм данных:

> with(dat, c2 * w)
[1] 2.0 1.5 6.0

Который мы можем вставить обратно в dat в одну строку:

> dat <- within(dat, c3 <- c2 * w)
> dat
   c1 c2   w  c3
1 abc  2 1.0 2.0
2 dxf  3 0.5 1.5
3 ghi  4 1.5 6.0

(Заменить c3 на c2, если вы хотите перезаписать существующий c2.)

Если у вас есть более одного числового столбца, отличного от весовых коэффициентов, вам потребуется немного другая стратегия, если вы хотите автоматизировать его (т.е. не указывать R, какие столбцы умножить на w).

> ## dummy data
> dat2 <- data.frame(c1 = c("abc","dxf","ghi"), c2 = 2:4, w = c(1,0.5,1.5),
                     c3 = 5:7, c4 = 3:5)
> ## select the columns we want, all numerics, but not `w`
> want <- sapply(dat2, is.numeric) & names(dat2) != "w"
> ## then use want to index into dat2
> dat2[, want] <- with(dat2, dat2[, want] * w)
> dat2
   c1  c2   w   c3  c4
1 abc 2.0 1.0  5.0 3.0
2 dxf 1.5 0.5  3.0 2.0
3 ghi 6.0 1.5 10.5 7.5
2 голосов
/ 23 февраля 2011

Просто для удовольствия попробуйте сделать это одной строкой (но на самом деле не самой читаемой!):

R> dd <- data.frame(G=gl(2,2), X=rnorm(4), Y=1L:4L, Z=letters[1:4], W=0.3:3.3)
R> dd
  G         X Y Z   W
1 1 0.2319565 1 a 0.3
2 1 0.4242205 2 b 1.3
3 2 0.5218064 3 c 2.3
4 2 0.7155944 4 d 3.3

R> data.frame(lapply(subset(dd, select=-W), function(v, w=dd$W) { if (is.numeric(v)) v*w else v }), W=dd$W)
  G          X    Y Z   W
1 1 0.06958695  0.3 a 0.3
2 1 0.55148670  2.6 b 1.3
3 2 1.20015475  6.9 c 2.3
4 2 2.36146163 13.2 d 3.3
1 голос
/ 23 февраля 2011

Как вы видели, есть несколько способов сделать это, но почему-то вы ожидаете один действительно простой способ, и я не знаю, существует ли он. В пакете plyr есть библиотечная функция, называемая colwise, которая близка, но я не могу придумать, как заставить ее делать именно то, что вы хотите. Лучшее, что я могу сделать с помощью colwise - это (при условии, что ваш фрейм данных называется df): <pre></p> <p>w2<-df$w df<-colwise(function(x,w){if(is.numeric(x)){x*w} else{x}})(df,df$w) df$w<-w2</p> <p>

Для тех, кто знаком с colwise, я не думаю, что вы можете просто использовать numcolwise, потому что тогда нечисловые столбцы вообще не выводятся. И я не могу придумать какой-либо простой способ не применять умножение к весу, поэтому я просто сохраняю и восстанавливаю его здесь. Я думаю, что если можно найти более чистый способ сделать это, colwise - хороший и простой способ сделать это.

...