优化跨越三个连续索引的公式的性能,并进行环绕

时间:2017-04-26 00:06:36

标签: r performance formula apply indices

我想优化此公式的实现。

以下是公式:formula

x是一组值。 i从1到N,其中N> 2400000。 对于i=0i-1是最后一个元素,对于i=lastElementi+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完成吗?

4 个答案:

答案 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来确定瓶颈位置的好例子。