我想优化此公式的实现。
x
是一组值。 i
从1到N,其中N> 2400000。
对于i=0
,i-1
是最后一个元素,对于i=lastElement
,i+1
是第一个元素。这是我写的代码:
x <- 1:2400000
re <- array(data=NA, dim = NROW(x))
lastIndex = NROW(x)
for(i in 1:lastIndex){
if (i==1) {
re[i] = x[i]*x[i] - x[lastIndex]*x[i+1]
} else if(i==lastIndex) {
re[i] = x[i]*x[i] - x[i-1]*x[1]
} else {
re[i] = x[i]*x[i] - x[i-1]*x[i+1]
}
}
可以由R中的apply
完成吗?
答案 0 :(得分:4)
我们可以使用直接矢量化
# Make fake data
x <- 1:10
n <- length(x)
# create vectors for the plus/minus indices
xminus1 <- c(x[n], x[-n])
xplus1 <- c(x[-1], x[1])
# Use direct vectorization to get re
re <- x^2 - xminus1*xplus1
答案 1 :(得分:1)
如果每个x[i]
确实等于i
那么你可以做一些数学运算:
xi ^ 2 - (xi-1)*(xi + 1)= 1
所以结果的所有元素都是1(只有第一个和最后一个不是1)
结果是:
c(1-2*N, rep(1, N-2), N*N-(N-1))
在一般情况下(x
中的任意值)你可以做(如Dason的回答):
x*x - c(x[N], x[-N])*c(x[-1], x[1])
以下是来自rollapply()
的{{1}}的解决方案:
zoo
以下是基准:
library("zoo")
rollapply(c(x[length(x)],x, x[1]), width=3, function(x) x[2]^2 - x[1]*x[3]) # or:
rollapply(c(tail(x,1), x, x[1]), width=3, function(x) x[2]^2 - x[1]*x[3])
答案 2 :(得分:0)
您的公式的lapply实现将如下所示:
x <- c(1:2400000)
last <- length(x)
re <- lapply(x, function(i) {
if(i == 1) {
x[i]*x[i] - x[last]*x[i+1]
} else if (i == last) {
x[i]*x[i] - x[i-1]*x[1]
} else {
x[i]*x[i] - x[i-1]*x[i+1]
}
})
re <- unlist(re)
lapply将返回一个列表,因此使用unlist()
完成向量的转换答案 3 :(得分:0)
1)你可以通过用最后一行和第一行的副本填充数组x的开头和结尾来避免计算中的所有特殊大小写;像这样的东西:
N <- NROW(x)
x <- rbind(x[N], x, x[1]) # pad start and end to give wraparound
re <- lapply(2:N, function(i) { x[i]*x[i] - x[i-1]*x[i+1] } )
#re <- unlist(re) as andbov wrote
# and remember not to use all of x, just x[2:N], elsewhere
2)直接矢量化,如@Dason的回答:
# Do the padding trick on x , then
x[2:N]^2 - x[1:N-1]*x[3:N+1]
3)如果性能很重要,我怀疑使用data.table
,否则on-loop on i会更快,因为它引用了三个连续的行。
4)为了获得更好的效果, use byte-compiling
5)如果你需要更快的速度,使用Rcpp扩展(引人注目的C ++)How to use Rcpp to speed up a for loop?
请参阅我引用的那些问题,以获得使用lineprof和microbenchmarking来确定瓶颈位置的好例子。