如何使用 dplyr 或 data.table 按数据子集组执行前瞻计算?
How to use dplyr or data.table to perform look-ahead calculations by groups of data subsets?
我有兴趣使用 dplyr(为了方便)and/or data.table(为了速度,因为要操作的实际数据有 300 万多行)执行“前瞻”计算一个数据集,按分组的子集,然后标记那些前瞻性计算 return 值为 0 的行。底部的图像更好地说明了我正在尝试做的事情,其中 State_1 是添加到原始 data
数据帧的列(例如通过 dplyr mutate(...)
)。有关如何执行此操作的任何建议?
掌握前瞻性计算会有很大帮助,这是我在 XLS 中一直笨拙地处理的事情。
从 data
数据框开始,紧接着生成代码:
> data
ID Period Values_1 Values_2 State
1 1 1 5 5 X0
2 1 2 0 2 X1
3 1 3 0 0 X2
4 1 4 0 12 X1
5 2 1 1 2 X0
6 2 2 0 0 X2
7 2 3 0 0 X0
8 2 4 0 0 X0
9 3 1 0 0 X2
10 3 2 0 0 X1
11 3 3 0 0 X9
12 3 4 0 2 X3
13 4 1 1 4 X2
14 4 2 2 5 X1
15 4 3 3 6 X9
16 4 4 0 0 X3
data <-
data.frame(
ID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4),
Period = c(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4),
Values_1 = c(5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0),
Values_2 = c(5, 2, 0, 12, 2, 0, 0, 0, 0, 0, 0, 2, 4, 5, 6, 0),
State = c("X0","X1","X2","X1","X0","X2","X0","X0", "X2","X1","X9","X3", "X2","X1","X9","X3")
)
这是我要完成的工作的示例:
我们可以使用分组方法 - 按 'ID' 分组,在 'Values' 列上循环 if_all
到 return TRUE 对于只有 0 个值的行,然后创建一个索引,其中 last
位置不是最后一次观察以及创建的索引和 replace
library(dplyr)
data %>%
group_by(ID) %>%
mutate(ind1 = if_all(starts_with('Values'), ~ .x == 0),
ind2 = last(which(ind1))== n() & ind1,
State_1 = replace(State, ind2, 'XX'), ind1 = NULL, ind2 = NULL) %>%
ungroup
-输出
# A tibble: 16 × 6
ID Period Values_1 Values_2 State State_1
<dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 1 1 5 5 X0 X0
2 1 2 0 2 X1 X1
3 1 3 0 0 X2 X2
4 1 4 0 12 X1 X1
5 2 1 1 2 X0 X0
6 2 2 0 0 X2 XX
7 2 3 0 0 X0 XX
8 2 4 0 0 X0 XX
9 3 1 0 0 X2 X2
10 3 2 0 0 X1 X1
11 3 3 0 0 X9 X9
12 3 4 0 2 X3 X3
13 4 1 1 4 X2 X2
14 4 2 2 5 X1 X1
15 4 3 3 6 X9 X9
16 4 4 0 0 X3 XX
一个data.table
解决方案。与其向前看,不如向后看。
setDT(data)[, State1 := ifelse(rev(cumsum(rev(Values_1 + Values_2))), State, "XX"), ID]
data
#> ID Period Values_1 Values_2 State State1
#> 1: 1 1 5 5 X0 X0
#> 2: 1 2 0 2 X1 X1
#> 3: 1 3 0 0 X2 X2
#> 4: 1 4 0 12 X1 X1
#> 5: 2 1 1 2 X0 X0
#> 6: 2 2 0 0 X2 XX
#> 7: 2 3 0 0 X0 XX
#> 8: 2 4 0 0 X0 XX
#> 9: 3 1 0 0 X2 X2
#> 10: 3 2 0 0 X1 X1
#> 11: 3 3 0 0 X9 X9
#> 12: 3 4 0 2 X3 X3
#> 13: 4 1 1 4 X2 X2
#> 14: 4 2 2 5 X1 X1
#> 15: 4 3 3 6 X9 X9
#> 16: 4 4 0 0 X3 XX
我有兴趣使用 dplyr(为了方便)and/or data.table(为了速度,因为要操作的实际数据有 300 万多行)执行“前瞻”计算一个数据集,按分组的子集,然后标记那些前瞻性计算 return 值为 0 的行。底部的图像更好地说明了我正在尝试做的事情,其中 State_1 是添加到原始 data
数据帧的列(例如通过 dplyr mutate(...)
)。有关如何执行此操作的任何建议?
掌握前瞻性计算会有很大帮助,这是我在 XLS 中一直笨拙地处理的事情。
从 data
数据框开始,紧接着生成代码:
> data
ID Period Values_1 Values_2 State
1 1 1 5 5 X0
2 1 2 0 2 X1
3 1 3 0 0 X2
4 1 4 0 12 X1
5 2 1 1 2 X0
6 2 2 0 0 X2
7 2 3 0 0 X0
8 2 4 0 0 X0
9 3 1 0 0 X2
10 3 2 0 0 X1
11 3 3 0 0 X9
12 3 4 0 2 X3
13 4 1 1 4 X2
14 4 2 2 5 X1
15 4 3 3 6 X9
16 4 4 0 0 X3
data <-
data.frame(
ID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4),
Period = c(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4),
Values_1 = c(5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0),
Values_2 = c(5, 2, 0, 12, 2, 0, 0, 0, 0, 0, 0, 2, 4, 5, 6, 0),
State = c("X0","X1","X2","X1","X0","X2","X0","X0", "X2","X1","X9","X3", "X2","X1","X9","X3")
)
这是我要完成的工作的示例:
我们可以使用分组方法 - 按 'ID' 分组,在 'Values' 列上循环 if_all
到 return TRUE 对于只有 0 个值的行,然后创建一个索引,其中 last
位置不是最后一次观察以及创建的索引和 replace
library(dplyr)
data %>%
group_by(ID) %>%
mutate(ind1 = if_all(starts_with('Values'), ~ .x == 0),
ind2 = last(which(ind1))== n() & ind1,
State_1 = replace(State, ind2, 'XX'), ind1 = NULL, ind2 = NULL) %>%
ungroup
-输出
# A tibble: 16 × 6
ID Period Values_1 Values_2 State State_1
<dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 1 1 5 5 X0 X0
2 1 2 0 2 X1 X1
3 1 3 0 0 X2 X2
4 1 4 0 12 X1 X1
5 2 1 1 2 X0 X0
6 2 2 0 0 X2 XX
7 2 3 0 0 X0 XX
8 2 4 0 0 X0 XX
9 3 1 0 0 X2 X2
10 3 2 0 0 X1 X1
11 3 3 0 0 X9 X9
12 3 4 0 2 X3 X3
13 4 1 1 4 X2 X2
14 4 2 2 5 X1 X1
15 4 3 3 6 X9 X9
16 4 4 0 0 X3 XX
一个data.table
解决方案。与其向前看,不如向后看。
setDT(data)[, State1 := ifelse(rev(cumsum(rev(Values_1 + Values_2))), State, "XX"), ID]
data
#> ID Period Values_1 Values_2 State State1
#> 1: 1 1 5 5 X0 X0
#> 2: 1 2 0 2 X1 X1
#> 3: 1 3 0 0 X2 X2
#> 4: 1 4 0 12 X1 X1
#> 5: 2 1 1 2 X0 X0
#> 6: 2 2 0 0 X2 XX
#> 7: 2 3 0 0 X0 XX
#> 8: 2 4 0 0 X0 XX
#> 9: 3 1 0 0 X2 X2
#> 10: 3 2 0 0 X1 X1
#> 11: 3 3 0 0 X9 X9
#> 12: 3 4 0 2 X3 X3
#> 13: 4 1 1 4 X2 X2
#> 14: 4 2 2 5 X1 X1
#> 15: 4 3 3 6 X9 X9
#> 16: 4 4 0 0 X3 XX