使用R中非相同索引的求和来矢量化(或加速)双循环

时间:2018-02-21 15:21:50

标签: arrays r loops matrix vectorization

我正在尝试优化设计用于计算两个方阵的元素乘积的双和的代码。假设我们有两个大小为 n W V 的平方矩阵。需要计算的对象是带有元素

的向量 B

简单来说:计算两个不同矩阵中两个不同行的逐个元素的乘积并取它们的和,然后在第二个矩阵的所有行上得到一个额外的总和(没有相同的索引)。

问题是,这个任务的计算复杂度看似 O(n 3 ),因为我们正在创建这个对象的长度, B ,是 n ,每个元素需要两个求和。这就是我想出的:

  1. 对于给定的 i j i≠j ),从 k 的内部和开始。所有 k 的总和,然后减去 k = i k = j 的项,并乘以 j≠的指标我
  2. 由于限制 j≠i 已在内部和中处理,因此外部总和仅用于 j = 1,...,n
  3. 如果我们表示,则两个步骤将如下所示

    但是,写一个循环结果非常低效。 n = 100 快速工作(0.05秒)。但是,例如,当 n = 500 时(我们在这里讨论实际应用程序),平均计算时间为3秒,对于 n = 1000 ,它跳到22秒。

    k 上的内部循环可以很容易地被一个和替换,但是外部的......在this question中,建议的解决方案是sapply,但它意味着必须对所有元素进行求和。

    这是我试图在宇宙热量死亡之前为大型 n 评估的代码。

    set.seed(1)
    N <- 500
    x1 <- rnorm(N)
    x2 <- rchisq(N, df=3)
    
    bw1 <- bw.nrd(x1)
    bw2 <- bw.nrd(x2)
    w <- outer(x1, x1, function(x, y) dnorm((x-y)/bw1) )
    w <- w/rowSums(w)
    
    v <- outer(x2, x2, function(x, y) dnorm((x-y)/bw2) )
    v <- v/rowSums(v)
    
    Bij <- matrix(NA, ncol=N, nrow=N)
    for (i in 1:N) { # Around 22 secs for N=1000
      for (j in 1:N) {
        Bij[i, j] <- (sum(w[i, ]*v[j, ]) - w[i, i]*v[j, i] - w[i, j]*v[j, j]) * (i!=j)
      }
    }
    Bi <- rowSums(Bij)
    

    专家 R 程序员如何对这种循环进行矢量化?

2 个答案:

答案 0 :(得分:3)

如果不查看矩阵wv的内容,可以使用一个矩阵乘法(tcrossprod)替换简单的矩阵运算,转置( t)和对角线提取:

Mat.ij <- tcrossprod(w, v) - 
    matrix(rep(diag(w), times = N), nrow = N) * t(v) - 
    w * matrix(rep(diag(v), each = N), nrow = N)
diag(Mat.ij) <- 0

all.equal(Bij, Mat.ij)
[1] TRUE

答案 1 :(得分:3)

<强>更新

事实上,考虑到你对B_ {ij}的表达,我们也可以做以下

diag(w) <- diag(v) <- 0
BBij <-  tcrossprod(w, v)
diag(BBij) <- 0

range(rowSums(BBij) - Bi)
# [1] -2.220446e-16  0.000000e+00
range(BBij - Bij)
# [1] -6.938894e-18  5.204170e-18

因此,虽然有些明显,但对于您的目的而言,它可能也是一个有趣的观察结果,B_ {ij}和B_i都不依赖于W和V的对角线。

初步回答:

由于 enter image description here 其中W和V的对角线可以设置为零,V _ {。k}表示V的第k列的总和,我们有

diag(w) <- diag(v) <- 0 
A <- w * v
rowSums(sweep(w, 2, colSums(v), `*`)) - rowSums(A) + diag(A)

,其中

range(rowSums(sweep(w, 2, colSums(v), `*`)) - rowSums(A) + diag(A) - Bi)
# [1] -1.110223e-16  1.110223e-16