如何使用中间结果变异新列,在R中累加或减少
我有一个具有以下结构的数据集my_df,dput添加在问题的末尾如何使用中间结果变异新列,在R中累加或减少,r,tidyverse,reduce,accumulate,R,Tidyverse,Reduce,Accumulate,我有一个具有以下结构的数据集my_df,dput添加在问题的末尾 > my_df group_id other_id case 1 1 1 add 2 1 1 add 3 1 11 add 4 1 1 replace 5 1 11 replace 6 1 1 replace 7
> my_df
group_id other_id case
1 1 1 add
2 1 1 add
3 1 11 add
4 1 1 replace
5 1 11 replace
6 1 1 replace
7 1 10 add
8 1 10 replace
9 2 2 add
10 2 10 add
11 2 10 replace
12 2 2 replace
13 2 3 add
14 2 3 replace
我想以tidyverse的方式创建一个新的列say collection,其中根据这两个条件,在group_id上为每个group_存储其他_id-
如果case为add,则当前行的其他_id将粘贴到此列的上一个值中
如果case=='replace',则当前行的其他_id将被替换为前一行计算的累积值中的任何内容
我想要的结果是
> result
group_id other_id case collection
1 1 1 add 1,
2 1 1 add 1,1,
3 1 11 add 1,1,11,
4 1 1 replace 1,11,
5 1 11 replace 1,
6 1 1 replace
7 1 10 add 10,
8 1 10 replace
9 2 2 add 2,
10 2 10 add 2,10,
11 2 10 replace 2,
12 2 2 replace
13 2 3 add 3,
14 2 3 replace
显然,每个组的末尾都会有空格,因为我的_df已经这样排列/排序了
我试图累积和减少,但我只能在case=='add'的情况下生成/累积值,我无法在下面的管道中应用str_replace。此外,我希望当case=='add'时,其他_id的值将粘贴到集合中,但仅粘贴到之前出现的值,无论它是否可能属于结果中不同的case行7和13
我尝试的语法只起了部分作用
library(tidyverse)
my_df %>% group_by(group_id) %>%
mutate(collection = case_when(case == "add" ~ accumulate(other_id, paste, sep=", "),
case == "replace" ~ "?"))
# A tibble: 14 x 4
# Groups: group_id [2]
group_id other_id case collection
<chr> <chr> <chr> <chr>
1 1 1 add 1
2 1 1 add 1, 1
3 1 11 add 1, 1, 11
4 1 1 replace ?
5 1 11 replace ?
6 1 1 replace ?
7 1 10 add 1, 1, 11, 1, 11, 1, 10
8 1 10 replace ?
9 2 2 add 2
10 2 10 add 2, 10
11 2 10 replace ?
12 2 2 replace ?
13 2 3 add 2, 10, 10, 2, 3
14 2 3 replace ?
谢谢你的期待
样本dput为
my_df <- structure(list(group_id = c("1", "1", "1", "1", "1", "1", "1",
"1", "2", "2", "2", "2", "2", "2"), other_id = c("1", "1", "11",
"1", "11", "1", "10", "10", "2", "10", "10", "2", "3", "3"),
case = c("add", "add", "add", "replace", "replace", "replace",
"add", "replace", "add", "add", "replace", "replace", "add",
"replace")), row.names = c(NA, -14L), class = "data.frame")
以下是使用累加器2的可能性:
以下是使用累加器2的可能性:
我的想法与@Cettt相同——使用累加器2。这里有一个使用正则表达式处理尾随逗号的选项
addOrRemove = function(acc, other_id, case) {
if(case == "add") {
ifelse(acc == "", other_id, paste(acc, other_id, sep = ", "))
} else {
sub(
paste0("((?<=^| )", other_id, "(, ))|((^|(, ))", other_id, "$)"),
"",
acc
,
perl = TRUE
)
}
}
my_df %>%
group_by(group_id) %>%
mutate(collection = unlist(accumulate2(other_id, case[-1], addOrRemove))
)
# A tibble: 14 x 4
# Groups: group_id [2]
group_id other_id case collection
<chr> <chr> <chr> <chr>
1 1 1 add "1"
2 1 1 add "1, 1"
3 1 11 add "1, 1, 11"
4 1 1 replace "1, 11"
5 1 11 replace "1"
6 1 1 replace ""
7 1 10 add "10"
8 1 10 replace ""
9 2 2 add "2"
10 2 10 add "2, 10"
11 2 10 replace "2"
12 2 2 replace ""
13 2 3 add "3"
14 2 3 replace ""
我的想法与@Cettt相同——使用累加器2。这里有一个使用正则表达式处理尾随逗号的选项
addOrRemove = function(acc, other_id, case) {
if(case == "add") {
ifelse(acc == "", other_id, paste(acc, other_id, sep = ", "))
} else {
sub(
paste0("((?<=^| )", other_id, "(, ))|((^|(, ))", other_id, "$)"),
"",
acc
,
perl = TRUE
)
}
}
my_df %>%
group_by(group_id) %>%
mutate(collection = unlist(accumulate2(other_id, case[-1], addOrRemove))
)
# A tibble: 14 x 4
# Groups: group_id [2]
group_id other_id case collection
<chr> <chr> <chr> <chr>
1 1 1 add "1"
2 1 1 add "1, 1"
3 1 11 add "1, 1, 11"
4 1 1 replace "1, 11"
5 1 11 replace "1"
6 1 1 replace ""
7 1 10 add "10"
8 1 10 replace ""
9 2 2 add "2"
10 2 10 add "2, 10"
11 2 10 replace "2"
12 2 2 replace ""
13 2 3 add "3"
14 2 3 replace ""
我最终能够做到这一点,而不需要通过之前定义的自定义函数来实现
my_df %>% group_by(group_id) %>%
mutate(new = unlist(accumulate2(other_id, case, ~if_else(..3 != "add", sub(paste0(..2, ","), "", ..1), paste0(..1, ..2, ",")), .init = "")[-1]))
# A tibble: 14 x 4
# Groups: group_id [2]
group_id other_id case new
<chr> <chr> <chr> <chr>
1 1 1 add "1,"
2 1 1 add "1,1,"
3 1 11 add "1,1,11,"
4 1 1 replace "1,11,"
5 1 11 replace "1,"
6 1 1 replace ""
7 1 10 add "10,"
8 1 10 replace ""
9 2 2 add "2,"
10 2 10 add "2,10,"
11 2 10 replace "2,"
12 2 2 replace ""
13 2 3 add "3,"
14 2 3 replace ""
我最终能够做到这一点,而不需要通过之前定义的自定义函数来实现
my_df %>% group_by(group_id) %>%
mutate(new = unlist(accumulate2(other_id, case, ~if_else(..3 != "add", sub(paste0(..2, ","), "", ..1), paste0(..1, ..2, ",")), .init = "")[-1]))
# A tibble: 14 x 4
# Groups: group_id [2]
group_id other_id case new
<chr> <chr> <chr> <chr>
1 1 1 add "1,"
2 1 1 add "1,1,"
3 1 11 add "1,1,11,"
4 1 1 replace "1,11,"
5 1 11 replace "1,"
6 1 1 replace ""
7 1 10 add "10,"
8 1 10 replace ""
9 2 2 add "2,"
10 2 10 add "2,10,"
11 2 10 replace "2,"
12 2 2 replace ""
13 2 3 add "3,"
14 2 3 replace ""
您能解释一下cur和new作为参数在这个自定义函数中做了什么吗?cur是当前值,即集合列中的前一个值。new是必须替换或添加的新值,即另一个_id列。感谢您的解释。我正在尝试使用现有的函数来实现它。我认为您使用自定义函数是因为sub接受三个参数,而Accumerate2只能容纳2个参数。我说得对吗?不,不太对。我使用了Accumerate2,因为给定行中集合的值取决于三个参数:前一个值和两个附加参数other_id和case。如果您希望实现一种不同的逻辑,其中collection的值仅取决于两个参数,则可以使用acculate。您的方法不起作用,因为使用acculate总是为整个tibble返回一个向量。如果不想编写自定义函数,可以在Accumerate2中使用匿名函数。请解释cur和new作为参数在此自定义函数中执行的操作。cur是当前值,即集合列中的上一个值。new是必须替换或添加的新值,即另一个_id列。感谢您的解释。我正在尝试使用现有的函数来实现它。我认为您使用自定义函数是因为sub接受三个参数,而Accumerate2只能容纳2个参数。我说得对吗?不,不太对。我使用了Accumerate2,因为给定行中集合的值取决于三个参数:前一个值和两个附加参数other_id和case。如果您希望实现一种不同的逻辑,其中collection的值仅取决于两个参数,则可以使用acculate。您的方法不起作用,因为使用acculate总是为整个tibble返回一个向量。如果您不想编写自定义函数,可以在Accumerate2中使用匿名函数。很抱歉,延迟接受。这符合我的目的。谢谢你迟到了。这符合我的目的。谢谢