沿矩阵行回收矢量的最快方法

时间:2016-10-24 21:23:15

标签: r

我有一个n x m矩阵mat和一个长度为m的向量vec。有没有一种快速的方法从矩阵的每一行中减去这个向量,并根据需要进行回收。

示例:

mat = structure(c(3.01, 1.44, 3.31, 1.34, 3.79, 1.65, 3.06, 1.12, 2.34, 
0.27, 2.63, 0.63, 2.73, 0.94, 3.1, 1.34, 2.75, 0.75, 2.83, 0.58
), .Dim = c(2L, 10L))

vec = colMeans(mat)

vec的每一行中减去mat的最快方法是什么? aperm似乎非常低效。

aperm(aperm(mat) - vec)

分配第二个矩阵也不是太漂亮了。

mat - matrix(vec, ncol=ncol(mat), nrow = nrow(mat), by.row =T)

注意:此问题是前一个问题的重新过帐,作为重复结束。不幸的是,重复项缺乏相关的,彻底的答案,因此我决定将其与答案一起添加。

1 个答案:

答案 0 :(得分:3)

library(microbenchmark)

byrow.speed.benchmark = function(ncol, nrow) {
  mat = matrix(rnorm(nrow * ncol), nrow = nrow, ncol = ncol)
  vec = colSums(mat)


  microbenchmark(
    aperm(aperm(mat) - vec),
    t(t(mat) - vec),
    mat - matrix(vec, ncol=ncol(mat), nrow = nrow(mat), byrow =T),
    sweep(mat, 2, vec),
    mat - rep(vec, each = nrow(mat)),
    #mat %*% diag(vec),
    mat - vec[col(mat)],
    mat - vec,
    times = 300
  )
}


byrow.speed.benchmark(10, 10)

比较几种跨矩阵行应用的方法,我们发现分配矢量是最快的。

Unit: nanoseconds
                                                             expr   min    lq      mean median    uq   max neval
                                          aperm(aperm(mat) - vec)  8642  9283 10214.287   9923 10243 80344   300
                                                  t(t(mat) - vec)  6722  7362  7950.130   8002  8323 27208   300
 mat - matrix(vec, ncol = ncol(mat), nrow = nrow(mat), byrow = T)  3201  3841  4282.947   4161  4482 20486   300
                                               sweep(mat, 2, vec) 26888 28489 30016.310  29448 30089 85145   300
                                 mat - rep(vec, each = nrow(mat))  2560  3201  3481.630   3521  3841 10883   300
                                              mat - vec[col(mat)]  1600  2241  2594.970   2561  2881  6081   300
                                                        mat - vec     0   320   389.530    320   321  1921   300

这如何缩放?

ncols = floor(10^((4:12)/4))
nrows = floor(10^((4:12)/4))

results = cbind(expand.grid(ncols, nrows), aperm = NA, t=NA, alloc = NA, sweep = NA, rep = NA,  indices=NA, control = NA)

for (i in seq(nrow(results))) {
  df = byrow.speed.benchmark(results[i,1], results[i,2])

  results[i,3:9] = sapply(split(df$time, as.numeric(df$expr)), mean)
}

library(ggplot2)

df = reshape2::melt(results, id.vars= c("Var1", "Var2"))

colnames(df) = c("ncol", "nrow", "method", "meantime")



ggplot(subset(df, ncol==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method))  + ggtitle("Scaling with cell number.") + coord_cartesian(ylim = c(0, 1E6))
ggplot(subset(df, ncol==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method))  + ggtitle("Scaling with cell number.") #+ coord_cartesian(ylim = c(0, 5E7))


ggplot(subset(df, ncol==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method)) + coord_cartesian(ylim = c(0, 3E7)) + ggtitle("Scaling with a wide matrix (1000 columns)")
ggplot(subset(df, nrow==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method)) + coord_cartesian(ylim = c(0, 3E7)) + ggtitle("Scaling with a tall matrix (1000 rows)")

粉色线是我们将矢量应用于内置回收的列的情况。使用matrix(vec, byrow=T)分配矩阵可以最大限度地扩展我们的选项。

Scaling with cell number Scaling with cell number, small number of cells

关于矩阵尺寸对此影响的可能性是对于宽矩阵和高矩阵的缩放。

Wide matrix Tall matrix

编辑:值得注意的是(正如预期的那样)矩阵分配不像矢量回收那样扩展。在这方面,上述情节略有误导。

Matrix vs recycling