Умножьте различные подмножества кадра данных на разные векторы - PullRequest
4 голосов
/ 30 июля 2011

Я хотел бы умножить несколько столбцов в моем фрейме данных на вектор значений.Конкретный вектор значений изменяется в зависимости от значения в другом столбце.

- РЕДАКТИРОВАТЬ -

Что если я сделаю набор данных более сложным, т. Е. Более 2 условий и условийслучайно перемешаны вокруг набора данных?

Вот пример моего набора данных:

df=data.frame(
  Treatment=(rep(LETTERS[1:4],each=2)),
  Species=rep(1:4,each=2),
  Value1=c(0,0,1,3,4,2,0,0),
  Value2=c(0,0,3,4,2,1,4,5),
  Value3=c(0,2,4,5,2,1,4,5),
  Condition=c("A","B","A","C","B","A","B","C")
  )

, который выглядит следующим образом:

 Treatment Species Value1 Value2 Value3 Condition
     A       1      0      0      0         A
     A       1      0      0      2         B 
     B       2      1      3      4         A
     B       2      3      4      5         C
     C       3      4      2      2         B
     C       3      2      1      1         A
     D       4      0      4      4         B
     D       4      0      5      5         C

Если Condition=="A",Я хотел бы умножить столбцы 3-5 на вектор c(1,2,3).Если Condition=="B", я бы хотел умножить столбцы 3-5 на вектор c(4,5,6).Если Condition=="C", я бы хотел умножить столбцы 3-5 на вектор c(0,1,0).Таким образом, результирующий фрейм данных будет выглядеть так:

 Treatment Species Value1 Value2 Value3 Condition
     A       1      0      0      0         A
     A       1      0      0     12         B 
     B       2      1      6     12         A
     B       2      0      4      0         C
     C       3     16     10     12         B
     C       3      2      2      3         A
     D       4      0     20     24         B
     D       4      0      5      0         C

Я попытался установить подмножество фрейма данных и умножить его на вектор:

t(t(subset(df[,3:5],df[,6]=="A")) * c(1,2,3))

Но я не могу вернуть подмножество данныхрамка к оригиналу.Есть ли способ выполнить эту операцию без поднабора фрейма данных, чтобы другие столбцы (например, «Лечение», «Виды») были сохранены?

Ответы [ 4 ]

9 голосов
/ 30 июля 2011

Вот довольно общее решение, которое вы сможете адаптировать под свои нужды.

Обратите внимание, что первый аргумент в вызове outer - это логический вектор, а второй - числовой, поэтому перед умножением TRUE и FALSE конвертируются в 1 и 0 соответственно.Мы можем добавить результаты outer, потому что условия не перекрываются и элементы FALSE будут равны нулю.

multiples <-
  outer(df$Condition=="A",c(1,2,3)) +
  outer(df$Condition=="B",c(4,5,6)) +
  outer(df$Condition=="C",c(0,1,0))

df[,3:5] <- df[,3:5] * multiples
2 голосов
/ 30 июля 2011

Вот не векторизованное, но простое для понимания решение:

 replaceFunction <- function(v){
   m <- as.numeric(v[3:5])
   if (v[6]=="A")
     out <- m * c(1,2,3)
   else if (v[6]=="B")
     out <- m * c(4,5,6)
   else
     out <- m
   return(out)
 }

 g <- apply(df, 1, replaceFunction)
 df[3:5] <- t(g)
 df
2 голосов
/ 30 июля 2011

Отредактировано, чтобы отразить некоторые примечания из комментариев

Предполагая, что Condition является фактором, вы можете сделать это:

#Modified to reflect OP's edit - the same solution works just fine
m <- matrix(c(1:6,0,1,0),3,3,byrow = TRUE)
df[,3:5] <- with(df,df[,3:5] * m[Condition,])

, который использует довольно быстрое векторизованное умножение. И, очевидно, завернуть это в with не обязательно, это просто то, что выскочило из моего мозга. Также обратите внимание на комментарий подгруппы ниже Backlin.

В более глобальном плане, помните, что каждое подмножество, которое вы можете сделать с subset, вы также можете сделать с [, и, что самое важное, [ назначить поддержку через [<-. Поэтому, если вы хотите изменить часть фрейма данных или матрицы, вы всегда можете использовать этот тип идиомы:

df[rowCondition,colCondition] <- <replacement values>

при условии, конечно, что <replacement values> - это то же измерение, что и ваше подмножество df. В противном случае это может сработать, но вы нарушите правила рециркуляции R, а R может дать предупреждение.

1 голос
/ 30 июля 2011
df[3:5] <- df[3:5] * t(sapply(df$Condition, function(x) if(x=="B") 4:6 else 1:3))

Или умножением вектора

df[3:5] <- df[3:5] * (3*(df$Condition == "B") %*% matrix(1, 1, 3)
                      + matrix(1:3, nrow(df), 3, byrow=T))
...