帮助加速R中的循环

时间:2010-10-27 15:22:48

标签: r loops

基本上我想在R中执行对角平均。下面是一些改编自simsalabim包的代码来进行对角线平均。只有这个很慢。

有关对此进行矢量化而不是使用sapply的任何建议吗?

reconSSA <- function(S,v,group=1){
### S : matrix
### v : vector

    N <- length(v)
    L <- nrow(S)
    K <- N-L+1
    XX <- matrix(0,nrow=L,ncol=K)
    IND <- row(XX)+col(XX)-1
    XX <- matrix(v[row(XX)+col(XX)-1],nrow=L,ncol=K)
    XX <- S[,group] %*% t(t(XX) %*% S[,group])

    ##Diagonal Averaging
    .intFun <- function(i,x,ind) mean(x[ind==i])

    RC <- sapply(1:N,.intFun,x=XX,ind=IND)
    return(RC)
}

对于数据,您可以使用以下

data(AirPassengers)
v <- AirPassengers
L <- 30
T <- length(v)
K <- T-L+1

x.b <- matrix(nrow=L,ncol=K)
x.b <- matrix(v[row(x.b)+col(x.b)-1],nrow=L,ncol=K)
S <- eigen(x.b %*% t(x.b))[["vectors"]] 
out <- reconSSA(S, v, 1:10)

2 个答案:

答案 0 :(得分:3)

借助rowsum的专业技巧,您可以将计算速度提高近10倍:

reconSSA_1 <- function(S,v,group=1){
### S : matrix
### v : vector
    N <- length(v)
    L <- nrow(S)
    K <- N-L+1
    XX <- matrix(0,nrow=L,ncol=K)
    IND <- row(XX)+col(XX)-1
    XX <- matrix(v[row(XX)+col(XX)-1],nrow=L,ncol=K)
    XX <- S[,group] %*% t(t(XX) %*% S[,group])
    ##Diagonal Averaging
    SUMS <- rowsum.default(c(XX), c(IND))
    counts <- if(L <= K) c(1:L, rep(L, K-L-1), L:1)
    else c(1:K, rep(K, L-K-1), K:1)
    c(SUMS/counts)
}

all.equal(reconSSA(S, v, 1:10), reconSSA_1(S, v, 1:10))
[1] TRUE

library(rbenchmark)

benchmark(SSA = reconSSA(S, v, 1:10),
          SSA_1 = reconSSA_1(S, v, 1:10),
          columns = c( "test", "elapsed", "relative"),
          order = "relative")


    test elapsed relative
2 SSA_1    0.23   1.0000
1   SSA    2.08   9.0435

[更新:正如Joshua所说,使用rowum代码的关键点可以进一步加速:

reconSSA_2 <- function(S,v,group=1){
### S : matrix
### v : vector
    N <- length(v)
    L <- nrow(S)
    K <- N-L+1
    XX <- matrix(0,nrow=L,ncol=K)
    IND <- c(row(XX)+col(XX)-1L)
    XX <- matrix(v[row(XX)+col(XX)-1],nrow=L,ncol=K)
    XX <- c(S[,group] %*% t(t(XX) %*% S[,group]))
    ##Diagonal Averaging
    SUMS <- .Call("Rrowsum_matrix", XX, 1L, IND, 1:N, 
                  TRUE, PACKAGE = "base")
    counts <- if(L <= K) c(1:L, rep(L, K-L-1), L:1)
    else c(1:K, rep(K, L-K-1), K:1)
    c(SUMS/counts)
}

   test elapsed  relative
3 SSA_2   0.156  1.000000
2 SSA_1   0.559  3.583333
1   SSA   5.389 34.544872

与原始代码相比, x34.5 的加速次数!!

答案 1 :(得分:0)

我无法得到你的榜样来产生明智的结果。我认为你的功能有几个错误。

  1. XX用于sapply,但未在函数
  2. 中定义
  3. sapply适用于1:N,您的示例中N=144x.b只有115列
  4. reconSSA只返回x
  5. 无论如何,我想你想要:

    data(AirPassengers)
    x <- AirPassengers
    rowMeans(embed(x,30))
    

    更新:我重新工作并分析了这个功能。大部分时间都花在mean上,因此使用R代码可能很难获得更快的速度。也就是说,您可以使用sum来加速20%。

    reconSSA <- function(S,v,group=1){
    
        N <- length(v)
        L <- nrow(S)
        K <- N-L+1
        XX <- matrix(0,nrow=L,ncol=K)
        IND <- row(XX)+col(XX)-1
        XX <- matrix(v[row(XX)+col(XX)-1],nrow=L,ncol=K)
        XX <- S[,group] %*% t(t(XX) %*% S[,group])
    
        ##Diagonal Averaging
        .intFun <- function(i,x,ind) {
            I <- ind==i
            sum(x[I])/sum(I)
        }
    
        RC <- sapply(1:N,.intFun,x=XX,ind=IND)
        return(RC)
    }