更快的i,j矩阵单元填充

时间:2014-05-22 21:26:41

标签: r performance data.table dplyr

我想获取data.frame / matrix的列并在数据帧的每个单元格([i, j])之间应用函数,其中i和j是data.frame列的序列。基本上我想填充单个单元格的矩阵,就像cor函数与data.frame一样。

这是一个相关的问题:Create a matrix from a function and two numeric data frames但是,我在随机化测试中使用它并多次重复操作(制作许多矩阵)。我正在寻找最快的方法来完成这项操作。我使用并行处理加快了一些事情,但我对这个速度仍然不满意。不能假设矩阵输出也是对称的,即cor产生对称矩阵的方式(我的例子将反映这一点)。

我今天在data.table网页上看到了http://datatable.r-forge.r-project.org/)以下内容:

  

DF[i,j]<-value

快500倍以上

这让我想到,或许data.tabledplyr或其他方式可能会加速一些事情。我的大脑已被固定在填充细胞上,但也许有更好的方法涉及重塑,应用函数并重新整形为矩阵或沿着这些线的东西。我可以使用outerfor循环在基本R中实现此目的,如下所示。

## Arbitrary function
FUN <- function(x, y) round(sqrt(sum(x)) - sum(y), digits=1)

## outer approach
outer(
  names(mtcars), 
  names(mtcars), 
  Vectorize(function(i,j) FUN(mtcars[,i],mtcars[,j]))
)

## for approach
mat <- matrix(rep(NA, ncol(mtcars)^2), ncol(mtcars))
for (i in 1:ncol(mtcars)) {
    for (j in 1:ncol(mtcars)) {
        mat[i, j] <- FUN(mtcars[, i], mtcars[, j])
    }
}
mat

以下microbenchmark时间安排for略有优势。

Unit: milliseconds
    expr      min       lq   median       uq      max neval
 OUTER() 4.450410 4.691124 4.774394 4.877724 55.77333  1000
   FOR() 4.309527 4.521785 4.588728 4.694156  7.04275  1000

R中最快的方法是什么(欢迎加入套餐)?

1 个答案:

答案 0 :(得分:3)

仍然坚持base R解决方案,我在基于for的方法中获得了1.6-1.7倍的加速:

  • [,i]代替[[i]](显着的时间影响 - 也许FUN只接收C指针而不是新分配的向量);
  • FUN的字节码编译(小时间影响);
  • for代码包装到函数+字节代码编译(小时间影响);
BTW,交换索引(i,j) - &gt; (j,i)在2个循环中没有导致显着差异(理论上,行方式矩阵访问应该更快)。

代码:

library(compiler)
FUN2 <- cmpfun(FUN)
for2 <- cmpfun(function(mtcars, FUN) {
      mat <- matrix(rep(NA, ncol(mtcars)^2), ncol(mtcars))
   for (i in 1:ncol(mtcars)) {
       for (j in 1:ncol(mtcars)) {
           mat[i, j] <- FUN(mtcars[[i]], mtcars[[j]])
       }
   }
   mat
})

基准:

 Unit: milliseconds
                min       lq   median       uq      max neval
 outer     7.791739 7.991474 8.245869 8.538163 16.24460   100
 for       8.143679 8.463249 8.588230 9.912008 16.30842   100
 for-mods  4.713837 4.875972 5.006202 5.246584 15.66491   100

在我看来,很难找到更快的方法(但我可能错了)。与多次计算for所需的时间相比,FUN循环时间偏差非常小(约0.25 ms)。