data.frame 中一个变量在另一个变量定义的步数中的滚动总和
Rolling sum of one variable in data.frame in number of steps defined by another variable
我正在尝试以累积的方式总结 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)
)
我正在尝试汇总组 a
中 b
的值。诀窍是,我想要 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))
我不确定是否可以在任何滚动函数中使用可变 window 大小。这是使用 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
这是包 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()
它可以灵活地适应不同的 window 尺寸。
输出:
# 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
是一个 couple-of-months-old tidyverse
包,专门用于滑动 window 函数。在这里查看更多信息:page, vignette
hop
是 slider
的引擎。使用此解决方案,我们将触发不同的 .start
和 .stop
以根据 a
组对 b
的值求和。
对于 _vec
,您要求 hop
到 return 向量:在这种情况下是双精度数。
row_number()
是一个 dplyr
函数,允许您 return 每组的行号,从而允许您沿着行滑动。
1) 滚动应用
rollapply
in zoo 支持矢量宽度。 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")
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]
我正在尝试以累积的方式总结 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)
)
我正在尝试汇总组 a
中 b
的值。诀窍是,我想要 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))
我不确定是否可以在任何滚动函数中使用可变 window 大小。这是使用 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
这是包 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()
它可以灵活地适应不同的 window 尺寸。
输出:
# 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
是一个 couple-of-months-old tidyverse
包,专门用于滑动 window 函数。在这里查看更多信息:page, vignette
hop
是 slider
的引擎。使用此解决方案,我们将触发不同的 .start
和 .stop
以根据 a
组对 b
的值求和。
对于 _vec
,您要求 hop
到 return 向量:在这种情况下是双精度数。
row_number()
是一个 dplyr
函数,允许您 return 每组的行号,从而允许您沿着行滑动。
1) 滚动应用
rollapply
in zoo 支持矢量宽度。 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")
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]