【问题标题】:how to calculate 5 days cumulative using apply family in R如何使用 R 中的应用族计算 5 天累积
【发布时间】:2016-01-22 16:41:48
【问题描述】:

我有一个 6940 行和 100 列的矩阵数据框。我需要在数据集上一次找到 5 天的累积时间。现在我能够为此构建一个 for 循环代码,如下所示:

cum<- matrix(data=q1,nrow=6940,ncol=100)
for (j in 1:100){
  for (i in 1:6940){
    cum[i,j]<-sum(q1[i,j],q1[i+1,j],q1[i+2,j],q1[i+3,j],q1[i+4,j],na.rm=T)
  }
}

我想知道apply家族中是否有任何函数可以做同样的事情,因为这段代码非常耗时。

例如,如果我使用命令生成数据框

 ens <- matrix(rnorm(200),20)

我想要一次 5 行的累积总和。即 row1:row5、row2:row6、row3:row7 等以数据框形式的总和。

我尝试以这种形式使用 apply 函数:

apply(apply(apply(apply( apply(m, 2, cumsum),2, cumsum), 2, cumsum),2,cumsum),2,cumsum)

但问题是我没有得到 5 个块的累积值,只有一个整体的累积值。

【问题讨论】:

标签: r for-loop statistics apply lapply


【解决方案1】:

这是一种使用stats::filter 函数计算滚动和并使用apply 循环列的方法:

m <- matrix(1:48, ncol = 4)
#      [,1] [,2] [,3] [,4]
# [1,]    1   13   25   37
# [2,]    2   14   26   38
# [3,]    3   15   27   39
# [4,]    4   16   28   40
# [5,]    5   17   29   41
# [6,]    6   18   30   42
# [7,]    7   19   31   43
# [8,]    8   20   32   44
# [9,]    9   21   33   45
#[10,]   10   22   34   46
#[11,]   11   23   35   47
#[12,]   12   24   36   48

apply(m, 2, filter, filter = rep(1, 5), sides = 1)
#      [,1] [,2] [,3] [,4]
# [1,]   NA   NA   NA   NA
# [2,]   NA   NA   NA   NA
# [3,]   NA   NA   NA   NA
# [4,]   NA   NA   NA   NA
# [5,]   15   75  135  195
# [6,]   20   80  140  200
# [7,]   25   85  145  205
# [8,]   30   90  150  210
# [9,]   35   95  155  215
#[10,]   40  100  160  220
#[11,]   45  105  165  225
#[12,]   50  110  170  230

这可能需要根据您希望如何处理少于 5 个值的窗口进行调整(例如,在开头)。

【讨论】:

  • 这种方法看起来很酷,我会用我的数据验证一次并将其标记为答案。真的很酷的东西人。 tnx :)
  • 能否请您解释一下代码真的很有帮助。尤其是在apply里面使用filter。 tnx
  • 阅读help("apply")。它需要一个类似矩阵的对象、边距(这里是列)、一个函数(这里是filter)和函数的进一步参数(这些请参见help("filter"))。
  • 在我的机器上尝试该方法时出现错误:> m apply(m, 2, filter, filter = rep( 1, 5), 边 = 1) UseMethod("filter_") 中的错误:没有适用于 'filter_' 的方法应用于“c('integer', 'numeric')”类的对象
  • 抱歉,我们需要在加载包统计信息之前加载包质量 :)
【解决方案2】:

另一个选项是roll_sum(来自@Roland 帖子的数据)

library(RcppRoll)
apply(m, 2, roll_sumr, 5)
#       [,1] [,2] [,3] [,4]
# [1,]   NA   NA   NA   NA
# [2,]   NA   NA   NA   NA
# [3,]   NA   NA   NA   NA
# [4,]   NA   NA   NA   NA
# [5,]   15   75  135  195
# [6,]   20   80  140  200
# [7,]   25   85  145  205
# [8,]   30   90  150  210
# [9,]   35   95  155  215
#[10,]   40  100  160  220
#[11,]   45  105  165  225
#[12,]   50  110  170  230

正如 cmets 中提到的@alexis_laz,roll_sumr 也可以采用矩阵。效率更高。

roll_sumr(m, 5, by = 1)

基准测试

set.seed(24)
m1 <- matrix(sample(1:50, 5000*5000, replace=TRUE), ncol=5000)
system.time(apply(m1, 2, roll_sumr, 5))
# user  system elapsed 
# 1.84    0.16    1.99 

system.time(roll_sumr(m1, 5, by = 1))
#  user  system elapsed 
#  0.59    0.15    0.74 

system.time(apply(m1, 2, stats::filter, filter = rep(1, 5), sides = 1))
#  user  system elapsed 
#  4.46    0.20    4.68 

【讨论】:

  • 我认为“RcppRoll”也可以处理矩阵,而无需 apply 循环。
  • roll_sumr(m, 5, by=1) 是对 alexis_laz 评论的回答
  • @alexis_laz 这样更好更高效。
【解决方案3】:

另一种不太复杂的方法:创建 5 个变量并按变量 5 时间求和。 这里:

m <- data.table(matrix(1:48, ncol = 4))
m[, index := .I]

m[, i1 := floor((index - 1) / 5) * 5 + 1]
m[, i2 := floor((index - 2) / 5) * 5 + 2]
m[, i3 := floor((index - 3) / 5) * 5 + 3]
m[, i4 := floor((index - 4) / 5) * 5 + 4]
m[, i5 := floor((index - 5) / 5) * 5 + 5]

cumsumm <- rbindlist(list(m[, list(value = sum(V1)), by = "i1"]
          , m[, list(value = sum(V1)), by = "i2"]
          , m[, list(value = sum(V1)), by = "i3"]
          , m[, list(value = sum(V1)), by = "i4"]
          , m[, list(value = sum(V1)), by = "i5"]), use.names=F)[i1 > 0, ]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多