0

次のコードを最適化しようとしています。

dim <- c(10000,100)

m <- matrix(sample(0:10, prod(dim), replace = TRUE), nrow = dim[1], ncol = dim[2])

system.time({

  output <- matrix(0, nrow = dim[1], ncol = dim[2])

  for (i in 1:dim[1]){        
    output[i,1] <- m[i,1]       
    for (j in 2:dim[2]){          
      output[i,j] <- output[i, j-1] * 0.5 + m[i,j]          
    }        
  }
})

概念的には、単純な累積合計と非常によく似ています。

system.time({

  output <- matrix(0, nrow = dim[1], ncol = dim[2])

  for (i in 1:dim[1]){       
      output[i,] <- cumsum(m[i,])        
  }
})

問題は、コードの最初の部分が約100倍遅いことです。トリックを行うカスタマイズされたバージョンのcumsum()を構築する方法はありますか?

4

2 に答える 2

2

あなたの場合は、係数 0.5 の AR(1) モデルを生成する場合とまったく同じです。filter関数を使用してデータを生成できます。filter高次の再帰、畳み込み、またはそれらの混合もサポートします(ARMAモデルについて考えてください)。convolve他の畳み込みを探しているかもしれません。また、コードをコンパイルしてループを高速化することもできます。私のコードでは、コンパイルされたループとコンパイルされていないループのコードは、フィルターよりもそれぞれ約 111 倍と 162 倍遅くなります。

library(compiler)
library(rbenchmark)

CustomCumsum<-function(x,alpha){
out<-x[1]
for(i in 2:length(x))
    out[i] <- out[i-1]*alpha+x[i]
out
}

compiledCustomCumsum<-cmpfun(CustomCumsum)

FilterCustomCumsum<-function(x,alpha) as.numeric(filter(x,alpha, method = "recursive"))

x<-rnorm(1000)
# Test whether they are the same
identical(compiledCustomCumsum(x,0.5) , FilterCustomCumsum(x,0.5) )

benchmark(
CustomCumsum=CustomCumsum(x,0.5),compiledCustomCumsum=compiledCustomCumsum(x,0.5),          FilterCustomCumsum=FilterCustomCumsum(x,0.5)
)

出力:

                  test replications elapsed relative user.self sys.self user.child sys.child
2 compiledCustomCumsum          100    8.89  111.125      8.78     0.01         NA        NA
1         CustomCumsum          100   13.02  162.750     11.84     0.50         NA        NA
3   FilterCustomCumsum          100    0.08    1.000      0.08     0.00         NA        NA
于 2013-02-11T16:11:58.857 に答える
2

私のカスタム累積関数を C で書くことは、他の何よりも非常に高速です。

sign <- signature(x="numeric", n="integer", d="numeric")

code <- "
  for (int i=1; i < *n; i++) {
    x[i] = x[i-1]*d[0] + x[i];
  }"

c_fn <- cfunction(sign,
                  code,
                  convention=".C"
)

CCustomCumsum <- function(vector, decay){
  c_fn(x=vector, n=length(vector), d=decay)$x
}

Julian のベンチマークを次のように実行します。

x<-rnorm(1000)
# Test whether they are the same
identical(compiledCustomCumsum(x,0.5) , FilterCustomCumsum(x,0.5) )

benchmark(
  CustomCumsum=CustomCumsum(x,0.5),
  compiledCustomCumsum=compiledCustomCumsum(x,0.5),
  FilterCustomCumsum=FilterCustomCumsum(x,0.5),
  CCustomCumsum = CCustomCumsum(x, 0.5)  
)

、私は得る:

                  test replications elapsed relative user.self sys.self user.child sys.child
4        CCustomCumsum          100   0.002      1.0     0.002    0.000          0         0
2 compiledCustomCumsum          100   0.631    315.5     0.536    0.095          0         0
1         CustomCumsum          100   0.931    465.5     0.882    0.046          0         0
3   FilterCustomCumsum          100   0.036     18.0     0.033    0.003          0         0
于 2013-02-11T19:50:16.887 に答える