【问题标题】:Subtract vector from matrix based on data.frame efficiently有效地从基于data.frame的矩阵中减去向量
【发布时间】:2020-05-27 17:25:21
【问题描述】:

我有一个矩阵X,两个数据帧AB 以及索引向量vec_avec_bAB 分别包含一个索引变量,其中的值对应于 vec_avec_b 中的值。除此之外,AB 包含与 X 中的列一样多的值:

# original data
X <- matrix(rnorm(200),100,2)

# values to substract in data.frames
A <- data.frame(index_a = 1:4, value1 = rnorm(4), value2 = rnorm(4))
B <- data.frame(index_b = 1:4, value1 = rnorm(4), value2 = rnorm(4))

# indices, which values to substract (one for each row of X)
vec_a <- sample(1:4, nrow(X), replace = T)
vec_b <- sample(1:4, nrow(X), replace = T)

我想要实现的是:对于X 中的每一行iii,根据向量@ 中的元素iiiAB 中获取值value1value2 987654341@ 和vec_b。然后,从X 中的相应行中减去这些值。可能听起来有点混乱,但我希望以下解决方案可以更清楚地说明目标是什么:

# iterate over all rows of X 
for(iii in 1:nrow(X)){

  # get correct values
  X_clean <- A[which(A$index_a == vec_a[iii]),-1] -    # subtract correct A value
             B[which(B$index_b == vec_b[iii]),-1]      # subtract correct B value

  # this intermediate step is necessary, otherwise we substract a data.frame from a matrix
  X_clean <- as.numeric(X_clean)  

  # subtract from X
  X[iii,] = X[iii,] - X_clean

}

请注意,在我的循环解决方案中,我们必须转换为numeric,否则X 将失去类matrix,因为我们从matrix 中减去data.frame。我的解决方案运行良好,直到您需要对许多矩阵(如 AB 以及数百万次观察)执行此操作。有没有不依赖循环遍历所有行的解决方案?

编辑

谢谢,这两个答案都大大提高了代码的速度。我选择了 StupidWolf 的答案,因为它比使用 data.table 更有效:

Unit: microseconds
        expr        min         lq       mean     median         uq        max neval cld
   datatable   5557.355   5754.931   6052.402   5881.729   5975.386  14154.040   100  b 
 stupid.wolf    818.529   1172.840   1311.784   1187.593   1221.164   4777.743   100 a  
        loop 111748.790 115141.149 116677.528 116109.571 117085.048 156497.999   100   c

【问题讨论】:

    标签: r matrix vector


    【解决方案1】:

    你可以只匹配行:

    set.seed(111)
    # original data
    X <- matrix(rnorm(200),100,2)
    
    A <- data.frame(index_a = 1:4, value1 = rnorm(4), value2 = rnorm(4))
    B <- data.frame(index_b = 1:4, value1 = rnorm(4), value2 = rnorm(4))
    
    vec_a <- sample(1:4, nrow(X), replace = T)
    vec_b <- sample(1:4, nrow(X), replace = T)
    
    newX <- X - as.matrix(A[match(vec_a,A$index_a),-1]-B[match(vec_b,B$index_b),-1])
    

    然后我们运行你的循环:

    for(iii in 1:nrow(X)){
    
      X_clean <- A[which(A$index_a == vec_a[iii]),-1] -    # subtract correct A value
                 B[which(B$index_b == vec_b[iii]),-1]      # subtract correct B value
    
      X_clean <- as.numeric(X_clean)  
      X[iii,] = X[iii,] - X_clean
    }
    

    并检查值是否相等:

    all.equal(c(newX),c(X))
    [1] TRUE
    

    匹配应该很快,但如果仍然太慢,您可以使用vec_a 调用A 的值,例如A[vec_a,] ..

    【讨论】:

      【解决方案2】:

      此方法使用data.table 方便加入。

      library(data.table)
      set.seed(111)
      X <- matrix(rnorm(200),100,2)
      A <- data.frame(index_a = 1:4, value1 = rnorm(4), value2 = rnorm(4))
      B <- data.frame(index_b = 1:4, value1 = rnorm(4), value2 = rnorm(4))
      vec_a <- sample(1:4, nrow(X), replace = T)
      vec_b <- sample(1:4, nrow(X), replace = T)
      setDT(A);setDT(B)
      dtX <- as.data.table(cbind(1:nrow(X),X,vec_a,vec_b))
      
      as.matrix(
        dtX[A, on = .(vec_a = index_a)][B,
            on = .(vec_b = index_b)][order(V1),
             .(V2 - (value1 - i.value1), V3 - (value2 - i.value2))]
        )
                  V1      V2
        [1,]  0.22746  0.7069
        [2,]  1.84340 -0.1258
        [3,] -0.70038  1.2494
      ...
       [98,]  2.04666  0.6767
       [99,]  0.02451  1.0473
      [100,] -2.72553 -0.6595
      

      希望这对于非常大的矩阵来说会非常快。

      【讨论】:

        猜你喜欢
        • 2013-12-02
        • 2018-10-14
        • 2014-10-21
        • 1970-01-01
        • 2014-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多