我正在尝试以累积方式汇总data.frame中的值。
我有这个:
df <- data.frame(
a = rep(1:2, each = 5),
b = 1:10,
step_window = c(2,3,1,2,4, 1,2,3,2,1)
)
我正在尝试汇总b
组中a
的值。诀窍是,我想要b
值的总和,该值与step_window
给定的当前行之后的行数相对应。
这是我正在寻找的输出:
data.frame(
a = rep(1:2, each = 5),
step_window = c(2,3,1,2,4,
1,2,3,2,1),
b = 1:10,
sum_b_step_window = c(3, 9, 3, 9, 5,
6, 15, 27, 19, 10)
)
我尝试使用RcppRoll
来执行此操作,但出现错误Expecting a single value
:
df %>%
group_by(a) %>%
mutate(sum_b_step_window = RcppRoll::roll_sum(x = b, n = step_window))
答案 0 :(得分:2)
我不确定在任何滚动功能中是否都可能具有可变的窗口大小。这是使用map2_dbl
的一种方法:
library(dplyr)
df %>%
group_by(a) %>%
mutate(sum_b_step_window = purrr::map2_dbl(row_number(), step_window,
~sum(b[.x:(.x + .y - 1)], na.rm = TRUE)))
# a b step_window sum_b_step_window
# <int> <int> <dbl> <dbl>
# 1 1 1 2 3
# 2 1 2 3 9
# 3 1 3 1 3
# 4 1 4 2 9
# 5 1 5 4 5
# 6 2 6 1 6
# 7 2 7 2 15
# 8 2 8 3 27
# 9 2 9 2 19
#10 2 10 1 10
答案 1 :(得分:2)
1)滚动应用
Zoo中的 rollapply
支持向量宽度。 partial=TRUE
说,如果宽度超过了末尾,则仅使用数据中的值。 (另一种可能性是使用fill=NA
代替,在这种情况下,如果没有足够的数据,它将用NA填充)。 align="left"
指定每一步的当前值是求和范围的左端。
library(dplyr)
library(zoo)
df %>%
group_by(a) %>%
mutate(sum = rollapply(b, step_window, sum, partial = TRUE, align = "left")) %>%
ungroup
2)SQL
这也可以在SQL中完成,方法是在指示的条件下将df与其自身连接起来,然后对条件匹配的所有行的每一行求和。
library(sqldf)
sqldf("select A.*, sum(B.b) as sum
from df A
left join df B on B.rowid between A.rowid and A.rowid + A.step_window - 1
and A.a = B.a
group by A.rowid")
答案 2 :(得分:1)
这是软件包slider
的解决方案。
library(dplyr)
library(slider)
df %>%
group_by(a) %>%
mutate(sum_b_step_window = hop_vec(b, row_number(), step_window+row_number()-1, sum)) %>%
ungroup()
在不同的窗口大小上都很灵活。
输出:
# A tibble: 10 x 4
a b step_window sum_b_step_window
<int> <int> <dbl> <int>
1 1 1 2 3
2 1 2 3 9
3 1 3 1 3
4 1 4 2 9
5 1 5 4 5
6 2 6 1 6
7 2 7 2 15
8 2 8 3 27
9 2 9 2 19
10 2 10 1 10
slider
是几个月前的tidyverse
软件包,专门用于滑动窗口功能。在这里查看更多信息:page,vignette
hop
是slider
的引擎。通过这种解决方案,我们可以触发不同的.start
和.stop
根据b
组对a
的值求和。
对于_vec
,您要让hop
返回一个向量:在这种情况下为双精度。
row_number()
是一种dplyr
函数,可让您返回每个组的行号,从而使您可以沿行滑动。
答案 3 :(得分:1)
data.table
使用累积和的解决方案
setDT(df)
df[, sum_b_step_window := {
cs <- c(0,cumsum(b))
cs[pmin(.N+1, 1:.N+step_window)]-cs[pmax(1, (1:.N))]
},by = a]