增长的矢量化

时间:2015-10-24 15:02:26

标签: r loops vectorization large-data

我正在寻找一种解决方案,通过在R:

中应用矢量化来实现以下简单增长率公式
gr <- function(x){
a <- matrix(,nrow=nrow(x),ncol=ncol(x))
   for (j in 1:ncol(x)){
      for (i in 2:nrow(x)){
        if (!is.na(x[i,j]) & !is.na(x[i-1,j]) & x[i-1,j] != 0){
           result[i,j] <- x[i,j]/x[i-1,j]-1 
        }
       }
    }
return(a)
}

我发现xts包会产生时间序列滞后,但最后我总是不得不与许多值进行比较(见上文),所以我不能简单地使用ifelse。一个可能的问题是当时间序列(例如价格指数)之间具有零。这会在结果中创建NaNs,我试图避免,之后不能简单地将其删除(编辑:显然他们可以,看下面的答案!)

简而言之:我希望为给定的值表生成一个正确增长率的表。这是一个例子:

m <- matrix(c(1:3,NA,2.4,2.8,3.9,0,1,3,0,2,1.3,2,NA,7,3.9,2.4),6,3)

产生

      [,1] [,2] [,3]
[1,]  1.0  3.9  1.3
[2,]  2.0  0.0  2.0
[3,]  3.0  1.0   NA
[4,]   NA  3.0  7.0
[5,]  2.4  0.0  3.9
[6,]  2.8  2.0  2.4

正确的结果,由gr(m)生成:

           [,1] [,2]       [,3]
[1,]        NA   NA         NA
[2,] 1.0000000   -1  0.5384615
[3,] 0.5000000   NA         NA
[4,]        NA    2         NA
[5,]        NA   -1 -0.4428571
[6,] 0.1666667   NA -0.3846154

但这需要大型表格。有没有办法在没有如此广泛的循环的情况下使用条件?

2 个答案:

答案 0 :(得分:6)

您可以通过在单个矢量化操作中执行整个计算来加快速度(使用一个额外的操作来在除以0时修复结果):

out <- rbind(NA, tail(m, -1) / head(m, -1) - 1)
out[!is.finite(out)] <- NA
out
#           [,1] [,2]       [,3]
#             NA   NA         NA
# [2,] 1.0000000   -1  0.5384615
# [3,] 0.5000000   NA         NA
# [4,]        NA    2         NA
# [5,]        NA   -1 -0.4428571
# [6,] 0.1666667   NA -0.3846154

这比循环解决方案快得多,如1000 x 1000示例所示:

set.seed(144)
m <- matrix(rnorm(10000000), 10000, 1000)
system.time(j <- josilber(m))
#    user  system elapsed 
#   1.425   0.030   1.446 
system.time(g <- gr(m))
#    user  system elapsed 
#  34.551   0.263  36.581 

矢量化解决方案提供25倍的加速。

答案 1 :(得分:3)

以下是两种方法:

1)没有包

rbind(NA, exp(diff(log(m)))-1)

,并提供:

          [,1] [,2]       [,3]
[1,]        NA   NA         NA
[2,] 1.0000000   -1  0.5384615
[3,] 0.5000000  Inf         NA
[4,]        NA    2         NA
[5,]        NA   -1 -0.4428571
[6,] 0.1666667  Inf -0.3846154

如果拥有第一行NA并不重要,那么它可以简化为exp(diff(log(m)))-1

2)动物园另一种方法是使用动物园的几何学差异函数。转换为动物园,取几何差异并减去1.如果有第一行NA很重要,则将其与具有原始时间点的零宽度系列合并(否则省略合并语句,只需使用g as答案):

library(zoo)

zm <- as.zoo(m)
g <- diff(zm, arithmetic = FALSE) - 1
merge(g, zoo(, time(zm))) # omit this line if 1st row of NAs not needed

giving:

        g.1 g.2        g.3
1        NA  NA         NA
2 1.0000000  -1  0.5384615
3 0.5000000 Inf         NA
4        NA   2         NA
5        NA  -1 -0.4428571
6 0.1666667 Inf -0.3846154