我正在尝试优化以下代码。
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()来实现这个技巧?
答案 0 :(得分:1)
您的情况与生成系数为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
答案 1 :(得分:1)
在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