【问题标题】:Multiply various subsets of a data frame by different vectors将数据帧的各种子集乘以不同的向量
【发布时间】:2011-10-16 06:33:13
【问题描述】:

我想将数据框中的几列乘以一个值向量。值的特定向量会根据另一列中的值而变化。

--编辑--

如果我让数据集更复杂,即超过 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))

但我无法将子集数据框返回到原始数据框。有没有什么方法可以在不对数据框进行子集化的情况下执行此操作,从而保留其他列(例如,Treatment、Species)?

【问题讨论】:

    标签: r vector subset multiplication


    【解决方案1】:

    已编辑以反映 cmets 的一些注释

    假设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 进行的每个子集设置也可以使用 [ 进行,更重要的是,[ 支持通过 [&lt;- 进行分配。所以如果你想改变数据框或矩阵的一部分,你总是可以使用这种类型的成语:

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

    当然假设&lt;replacement values&gt;df 的子集的维度相同。否则它可能会起作用,但你会违反 R 的回收规则,并且 R 可能会发出警告。

    【讨论】:

    • 或者df[3:5] &lt;- df[3:5] * t(matrix(1:6, 3, 2)[,df$Condition])怎么样?更紧凑。如果要获取整个列,则在索引数据帧时不需要逗号,并且在用于索引时因子会自动解释为整数。
    • 我完全同意as.integer 是不必要的。但是,我通常更喜欢在子集时明确说明我是否打算将其应用于行/列,但这是风格问题。就个人而言,我发现这样更容易阅读。但是,你总是可以把这些东西挑到死。我的意思是,我使用with 来避免输入df$! ;)
    • 哈哈,没错。有时我会因为试图尽可能努力地压缩所有内容而得意忘形。但是with毕竟比df$长一个字母,想想你可以用你浪费的那封信写的一切!
    【解决方案2】:

    这是一个相当通用的解决方案,您应该能够根据自己的需要进行调整。

    注意outer 调用中的第一个参数是逻辑向量,第二个参数是数字,所以在乘法之前TRUEFALSE 分别转换为10。我们可以添加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
    

    【讨论】:

    • +1 真的需要让我的大脑围绕这些内部/外部功能。感谢您的使用案例。
    • 也很好用,虽然不太确定它在做什么。谢谢!
    【解决方案3】:

    这是一个非矢量化但易于理解的解决方案:

     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
    

    【讨论】:

    • 很好的答案!做到了,我终于能够成功地实现 if else 语句。当我将df[3:5]=t(g) 应用到更大的数据集时,R 确实在df[3:5]=t(g) 之后发出了警告,但这些值在数据框中正确显示。
    【解决方案4】:
    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))
    

    【讨论】:

    • 嗯,有趣的方法。如果我有多个条件,我将如何整合 if else 语句? (见上文)
    • 我会选择 joran 建议的东西。制作一个矩阵,其中的行对应于每个可能的情况,然后以某种巧妙的方式对它们进行索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-12
    • 1970-01-01
    相关资源
    最近更新 更多