我有一个数据框列表,
a
,b
,和c
。我想得到一个列表,其中 a
不会被更改,b
将只包含那些不在 a
中的行,而 c
将只包含那些不在 b
. 中的行
# Sample data
a <- data.frame(num = 1:4, let = letters[1:4])
b <- data.frame(num = 2:6, let = letters[2:6])
c <- data.frame(num = 3:8, let = letters[3:8])
dfs <- list(a, b, c)
让我感到困惑的部分是我需要在 original 之前的数据帧上执行反连接,而不是在反连接到其之前的数据帧之后创建的数据帧。我的直觉是使用
accumulate
中的 purrr
来执行此操作,但我无法弄清楚如何让它在原始的先前数据帧上工作。
dfs |>
accumulate(~anti_join(.y, .x))
[[1]]
num let
1 1 a
2 2 b
3 3 c
4 4 d
[[2]]
num let
1 5 e
2 6 f
[[3]]
num let
1 4 d
2 7 g
3 8 h
因为这加入了已经加入的先前数据框,所以我在第三个 df 中有
4 d
,这是我不想要的。
我已经尝试过
.dir = "backward"
作为使用原始dfs加入的一种方式,但这并没有做我认为应该做的事情:
dfs |>
accumulate(~anti_join(.y, .x), .dir = "backward")
[[1]]
num let
1 7 g
2 8 h
[[2]]
num let
1 7 g
2 8 h
[[3]]
num let
1 4 d
2 5 e
3 6 f
4 7 g
5 8 h
有没有办法设置
accumulate
的参数,这样它就可以做到这一点,或者我需要一种不同的方法吗?如果可能的话,我更喜欢 purrr/tidyverse,但我愿意接受任何满足我需要的东西。
预期产出:
[[1]]
num let
1 1 a
2 2 b
3 3 c
4 4 d
[[2]]
num let
1 5 e
2 6 f
[[3]]
num let
1 7 g
2 8 h
accumulate
是为动态排序而设计的,这里你需要一个锚点,df[[1]]
,以及一个应用于列表其余元素的函数:
dfs[-1] <- map(dfs[-1], ~ anti_join(.x, dfs[[1]]))
[[1]]
num let
1 1 a
2 2 b
3 3 c
4 4 d
[[2]]
num let
1 5 e
2 6 f
[[3]]
num let
1 5 e
2 6 f
3 7 g
4 8 h
您可以使用
map_at()
选择性地将 anti_join
应用于除第一个之外的每个 data.frame。
map_at(dfs, -1, ~ anti_join(.x, dfs[[1]]))
[[1]]
num let
1 1 a
2 2 b
3 3 c
4 4 d
[[2]]
num let
1 5 e
2 6 f
[[3]]
num let
1 5 e
2 6 f
3 7 g
4 8 h
只用
dplyr
,你可以做:
dfs %>%
bind_rows(., .id = "df") %>%
filter(!(duplicated(num) & duplicated(let))) %>%
group_split(df, .keep = FALSE)
[[1]]
# A tibble: 4 × 2
num let
<int> <chr>
1 1 a
2 2 b
3 3 c
4 4 d
[[2]]
# A tibble: 2 × 2
num let
<int> <chr>
1 5 e
2 6 f
[[3]]
# A tibble: 2 × 2
num let
<int> <chr>
1 7 g
2 8 h