当函数依赖于index和mutate()效率时,apply()

时间:2017-09-26 12:47:50

标签: r performance dplyr tidyr

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

的内容
Y[i,j] = i*j*X[i,j]

使用for循环比其他选项慢很多,而apply()不知道它正在使用哪个i和j。

我能想到的一个解决方案是使用列i,j,X定义一个类似数据帧的对象,然后使用mutate()来获得所需的Y值。

我有两个问题:

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

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

2 个答案:

答案 0 :(得分:4)

根据矩阵的大小和稀疏度,您可以尝试的第一件事是使用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,但需要额外的内存。

答案 1 :(得分: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 ms)。

# 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