在处理 2023 年代码降临第 9 天的编码选项时出现了这个问题。假设我们有一个列表 col 对象,其中一列包含 tibbles。每个小标题都有一个变量
aa
。目标是一个新变量 bb
,它是当下面所有 aa
值为零时 aa
的值。从那时起,bb
将被计算为:aa + lead(bb)
;即从当前行开始将 aa
与下面一行的 bb
相加。
这是一个可重现的示例:
dat <- tibble(
V1 = sample(LETTERS, 3),
V2 = rnorm(3, 100, 50),
V3 = list(
tibble(var_not_used = sample(LETTERS, 5), aa = c(15, 3, 0, 0 ,0)),
tibble(var_not_used = sample(LETTERS, 5), aa = c(21, 6, 1, 0, 0)),
tibble(var_not_used = sample(LETTERS, 5), aa = c(45, 15, 6, 2, 0))
)
)
小标题 1 中的 bb
应该是 18, 3, 0, 0, 0
;小标题 2 中的 bb
应该是 28, 7, 1, 0, 0
;小标题 3 中的 bb
应该是 68, 23, 8, 2, 0
。下面是一个尝试/说明它应该朝哪个方向发展。
我们怎样才能优雅地编写代码以仅获得一列
bb
?我对 tidyverse 解决方案特别感兴趣;取消嵌套是一个选项,但如果解决方案直接作用于嵌套对象,那就太好了。
dat <- tibble(
V1 = sample(LETTERS, 3),
V2 = rnorm(3, 100, 50),
V3 = list(
tibble(var_not_used = sample(LETTERS, 5), aa = c(15, 3, 0, 0 ,0)),
tibble(var_not_used = sample(LETTERS, 5), aa = c(21, 6, 1, 0, 0)),
tibble(var_not_used = sample(LETTERS, 5), aa = c(45, 15, 6, 2, 0))
)
) %>%
## from here on: this returns the data that we are interested in; however,
## its a lot of code repetition and many new columns. Moreover, in reality
## we might face situations in which we had to do way more than 4 of these
## mutate's
mutate(
V3 = map(V3, ~ .x %>%
mutate(bb1 = case_when(
lead(aa) == 0 ~ aa + lead(aa, default = 0)
))
)
) %>%
mutate(
V3 = map(V3, ~ .x %>%
mutate(bb2 = case_when(
is.na(bb1) ~ aa + lead(bb1, default = 0)
))
)
) %>%
mutate(
V3 = map(V3, ~ .x %>%
mutate(bb3 = case_when(
is.na(bb2) ~ aa + lead(bb2, default = 0)
))
)
) %>%
mutate(
V3 = map(V3, ~ .x %>%
mutate(bb4 = case_when(
is.na(bb3) ~ aa + lead(bb3, default = 0)
))
)
)
看起来
bb
只是aa
的逆累加和,所以我们可以这样做:
dat %>%
mutate(V3 = map(V3, ~ .x %>% mutate(bb = rev(cumsum(rev(aa))))))
我们可以通过拉出列表列来查看它的样子:
dat %>%
mutate(V3 = map(V3, ~ .x %>% mutate(bb = rev(cumsum(rev(aa)))))) %>%
pluck('V3')
#> [[1]]
#> # A tibble: 5 x 3
#> var_not_used aa bb
#> <chr> <dbl> <dbl>
#> 1 W 15 18
#> 2 K 3 3
#> 3 G 0 0
#> 4 Q 0 0
#> 5 F 0 0
#>
#> [[2]]
#> # A tibble: 5 x 3
#> var_not_used aa bb
#> <chr> <dbl> <dbl>
#> 1 P 21 28
#> 2 O 6 7
#> 3 A 1 1
#> 4 W 0 0
#> 5 M 0 0
#>
#> [[3]]
#> # A tibble: 5 x 3
#> var_not_used aa bb
#> <chr> <dbl> <dbl>
#> 1 M 45 68
#> 2 B 15 23
#> 3 Y 6 8
#> 4 A 2 2
#> 5 T 0 0