您可以使用rollsumr
函数从zoo
为此的包:
library(zoo)
test$sums <- rollsumr(test$vals, k = 3, fill = NA)
这使:
> test
id vals sums
1 1 4 NA
2 2 7 NA
3 3 2 13
4 4 9 18
5 5 7 18
6 6 0 16
7 7 4 11
8 8 6 10
9 9 1 11
10 10 8 15
这与使用相同rollsum
函数与align = 'right'
范围:
rollsum(test$vals, k = 3, fill = NA, align = 'right')
作为替代方案,您可以使用Reduce
with shift
来自数据表 /questions/tagged/data.table包裹:
library(data.table)
setDT(test)[, sums := Reduce(`+`, shift(vals, 0:2))]
这给出了相同的结果:
> test
id vals sums
1: 1 4 NA
2: 2 7 NA
3: 3 2 13
4: 4 9 18
5: 5 7 18
6: 6 0 16
7: 7 4 11
8: 8 6 10
9: 9 1 11
10: 10 8 15
最近新增了快速滚动功能数据表 /questions/tagged/data.table。因此,另一种选择是:
setDT(test)[, sums := frollsum(vals, 3)]
@alexis_laz 在评论中提出的一个很好的基本 R 替代方案:
n <- 3
cs <- cumsum(test$vals)
test$sums <- c(rep_len(NA, n - 1), tail(cs, -(n - 1)) - c(0, head(cs, -n)))
@Khashaa 在评论中提出的另外两个选项:
# with base R
n <- 3
test$sums <- c(rep_len(NA, n - 1), rowSums(embed(test$vals, n)))
# with RcppRoll
library(RcppRoll)
test$sums <- roll_sumr(test$vals, 3)
基准:
As @alexis_laz 在评论中指出 https://stackoverflow.com/questions/37773356/find-sum-of-previous-n-rows-in-dataframe/37773562#comment63017758_37773562,某些解决方案可能会在重新计算总和和重新创建时产生开销length
-向量。这可能会导致计算速度的差异。由于在如此小的数据集上进行基准测试并没有多大意义,因此我将在模仿示例数据集的大型数据集上对不同的解决方案进行基准测试:
# window size
n <- 3
# creating functions of the different solutions:
alexis_laz <- function(test) {cs <- cumsum(test$vals); test$sums <- c(rep_len(NA, n - 1), tail(cs, -(n - 1)) - c(0, head(cs, -n)))}
khashaa <- function(test) {test$sums <- c(rep_len(NA, n - 1), rowSums(embed(test$vals, n)))}
rcpp_roll <- function(test) test$sums <- roll_sumr(test$vals, n)
zoo_roll <- function(test) test$sums <- rollsumr(test$vals, k=n, fill=NA)
dt_reduce <- function(test) setDT(test)[, sums := Reduce(`+`, shift(vals, 0:(n-1)))]
dt_froll <- function(test) setDT(test)[, sums := frollsum(vals, n)]
# load the 'bench' package
library(bench)
# create a big test dataset
test <- data.frame(id=rep(1:10,1e7), vals=sample(c(4,7,2,9,7,0,4,6,1,8),1e7,TRUE))
# run the benchmark
big_bm <- mark(alexis_laz(test),
khashaa(test),
rcpp_roll(test),
zoo_roll(test),
dt_reduce(test),
dt_froll(test),
iterations = 1,
check = FALSE)
# extract some core measures and sort them
big_bm %>% select(expression, median, mem_alloc) %>% arrange(median)
这使:
expression median mem_alloc
<bch:expr> <bch:tm> <bch:byt>
1 dt_froll(test) 776.35ms 1.49GB
2 rcpp_roll(test) 1.23s 762.94MB
3 dt_reduce(test) 2.12s 4.47GB
4 alexis_laz(test) 3.68s 4.47GB
5 khashaa(test) 8.35s 5.21GB
6 zoo_roll(test) 33.32s 22.63GB
正如你所看到的,新的frollsum
- 函数来自数据表 /questions/tagged/data.table-package 在速度方面显然是赢家。当考虑内存分配时,roll_sumr
from rcpproll /questions/tagged/rcpproll需要最少的内存。