在R中两个瘦高的矩阵之间计算行方式点积的最快方法

时间:2016-10-24 22:30:15

标签: r

考虑A和B是两个尺寸为10 ^ 8 X 5的高密度矩阵。 即;

rowSums(A * B)

我想计算A的每一行的点积与B的相应行,即

{{1}}

但它很慢,我想知道是否有更快的方法。

1 个答案:

答案 0 :(得分:2)

这可能让你失望,但在R级别,这已经是你自己不用编写一些C代码就能获得的最好成绩。问题在于,通过rowSums(A * B),您实际上正在做

C <- A * B
rowSums(C)

第一行执行三个大型高薄矩阵的全扫描;而第二行执行1个大型高薄矩阵的全扫描。总而言之,我们等效地扫描了4倍高密度矩阵(内存密集型)。

事实上,对于此类操作,最佳算法只需要扫描n * p高 - 薄矩阵两次,方法是 rowwise cross product

rowsum <- numeric(n)
for j = 1, 2, ... p
  rowsum += A[,i] * B[,i]

通过这种方式,我们也避免生成矩阵C。注意,上面只是一个假代码,而不是有效的R代码甚至是C代码。但这个想法很清楚,我们想用C编写这个。

与您的情况类比的是sum(x * y)crossprod(x, y)之间的速度差异,假设xy是相同长度的大型向量。

x <- runif(1e+7)
y <- runif(1e+7)

system.time(sum(x * y))
#   user  system elapsed 
#  0.124   0.032   0.158 

system.time(crossprod(x, y))
#   user  system elapsed 
#  0.036   0.000   0.056 

在第一种情况下,我们扫描长矢量4次,而在第二种情况下,我们只扫描它两次。

统计计算的相关性

rowSums(A * B)实际上是diag(tcrossprod(A, B))的有效评估,常见于与逐点预测方差相关的回归计算中。例如,在来自模型矩阵的QR因子分解的具有薄Q矩阵的普通线性正方形回归中,拟合值的逐点方差是diag(tcrossprod(Q)),其由rowSums(Q ^ 2)更有效地计算。但是,由于已经解释过的原因,这仍然不是最快的评估。