【问题标题】:apply() when function depends on index and mutate() efficiencyapply() 当函数依赖于索引和 mutate() 效率时
【发布时间】:2017-09-26 12:47:50
【问题描述】:

我想知道,例如,假设您想要转换一些矩阵,并且您想要类似

Y[i,j] = i*j*X[i,j]

使用 for 循环比其他选项慢很多,并且 apply() 不知道它使用的是哪个 i 和 j。

我能想到的一个解决方案是定义一个类似于 data.frame 的对象,其中包含 i、j、X 列,然后使用 mutate() 来获取所需的 Y 值。

我有两个问题:

(a) 是否可以使用 apply() 而不是 for 循环来构造上述矩阵?如果有,以这种方式构造它还是使用 mutate() 技巧更有效?

(b) 假设我有 matrix 和 data.frame 对象表示。如果我想做包含行和列索引的操作,哪个更有效?例如,如果想要一个统计数据,例如 (Y[i,j] - mean(Y))²/(i*j) 之和。我知道我可以用 row 和 col 索引构造矩阵,然后只使用向量化函数,但它比使用 mutate 更好吗?

【问题讨论】:

    标签: r performance dplyr tidyr


    【解决方案1】:

    根据您的矩阵的大小和稀疏程度,您可以尝试的第一件事是使用rowcol 函数分别构造rowcolumn 索引,然后用它来转换您的矩阵:

    X <- matrix(1:9, 3, 3)
    
    row(X) * col(X) * X
    #     [,1] [,2] [,3]
    #[1,]    1    8   21
    #[2,]    4   20   48
    #[3,]    9   36   81
    

    那么对于(Y[i,j] - mean(Y))²/(i*j),类似:

    Y <- row(X) * col(X) * X
    (Y - mean(Y)) ^ 2 / (row(Y) * col(Y))
    
    #          [,1]       [,2]       [,3]
    #[1,] 592.11111 150.222222   6.259259
    #[2,] 227.55556   7.111111  85.629630
    #[3,]  88.92593  18.962963 344.308642
    

    这是完全矢量化的方法,不需要applyfor loop,但需要额外的内存。

    【讨论】:

      【解决方案2】:

      我认为outer 可能比row(X) * col(X) 更快。

      # Define dimensions
      n.rows <- n.cols <- 1000
      
      # Define matrix
      X <- matrix(runif(n.rows * n.cols), ncol = n.cols)
      
      # Psidom's approach
      rowcol.method <- function(X){row(X) * col(X) * X}
      
      # Approach using outer
      outer.method <- function(X){outer(1:nrow(X), 1:ncol(X)) * X}
      
      # Benchmark library
      library(microbenchmark)
      
      # Test
      microbenchmark(
        rowcol.method(X),
        outer.method(X)
      )
      

      结果:

      Unit: milliseconds
                   expr       min        lq      mean    median        uq      max neval cld
       rowcol.method(X) 20.895870 21.154815 23.795695 21.612485 22.584323 62.50660   100   b
        outer.method(X)  5.608577  5.729724  6.883643  5.836526  5.977156 50.12508   100  a 
      

      比较输出:

      identical(rowcol.method(X), outer.method(X))
      [1] TRUE
      

      对于其他计算类似,尽管外部方法有一个疯狂的异常值(221.66718 毫秒)。

      # Define matrix
      Y <- row(X) * col(X) * X
      
      # Psidom's approach
      rowcol.method.Y <- function(Y) {(Y - mean(Y)) ^ 2 / (row(Y) * col(Y))}
      
      # Approach using outer
      outer.method.Y <- function(Y) {(Y - mean(Y)) ^ 2 / outer(1:nrow(X), 1:ncol(X))}
      
      # Test
      microbenchmark(
        rowcol.method.Y(Y),
        outer.method.Y(Y)
      )
      

      结果:

      Unit: milliseconds
                     expr      min       lq     mean   median       uq       max neval cld
       rowcol.method.Y(Y) 27.94405 30.18635 34.63551 33.32627 37.06467  46.58983   100   b
        outer.method.Y(Y) 11.27064 12.66349 18.77192 15.66756 18.18864 221.66718   100  a 
      

      比较输出:

      identical(rowcol.method.Y(Y), outer.method.Y(Y))
      [1] TRUE
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-09-08
        • 2015-07-02
        • 1970-01-01
        • 2014-08-19
        • 2021-09-29
        • 1970-01-01
        • 2014-07-02
        相关资源
        最近更新 更多