full_join、right_join 的 R 替代方案,在不增加行的情况下合并?

R alternative to full_join, right_join, merge without increasing rows?

考虑 2 个 dfs:

df1:

Col A Col B Col C
Tom Ice Cream 0.2
Tom Candy 0.4
Tom Lollipop 0.6
Bob Sweets 0.1
Abe Sweets 0.1

df2:

Col A Col D Col E
Tom Sweets 0.5
Tom Chocolate 0.2
Tom Cola 0.3

如果我将 full_joinright_joinmergeby = "Col A"(与 all.y=TRUE)一起使用,我会得到每个“排列”作为自己的行:

df3:

Col A Col B Col C Col D Col E
Tom Ice Cream 0.2 Sweets 0.5
Tom Ice Cream 0.2 Chocolate 0.2
Tom Ice Cream 0.2 Cola 0.3
Tom Candy 0.4 Sweets 0.5
Tom Candy 0.4 Chocolate 0.2
Tom Candy 0.4 Cola 0.3
Tom Lollipop 0.6 Sweets 0.5
Tom Lollipop 0.6 Chocolate 0.2
Tom Lollipop 0.6 Cola 0.3
Bob Sweets 0.1 N/A N/A
Abe Sweets 0.1 N/A N/A

如果我将 inner_joinleft_joinmergeby = "Col A"(没有 all.y=TRUE)一起使用,除了子集化为只有被操作的行,例如,包含 Abe 和 Bob 的行将被删除:

df4:

Col A Col B Col C Col D Col E
Tom Ice Cream 0.2 Sweets 0.5
Tom Ice Cream 0.2 Chocolate 0.2
Tom Ice Cream 0.2 Cola 0.3
Tom Candy 0.4 Sweets 0.5
Tom Candy 0.4 Chocolate 0.2
Tom Candy 0.4 Cola 0.3
Tom Lollipop 0.6 Sweets 0.5
Tom Lollipop 0.6 Chocolate 0.2
Tom Lollipop 0.6 Cola 0.3

我正在尝试在不增加行数的情况下进行合并,因为唯一排列并不重要。他们加入的顺序也无关紧要。预期输出:

df5:

Col A Col B Col C Col D Col E
Tom Ice Cream 0.2 Sweets 0.5
Tom Candy 0.4 Chocolate 0.2
Tom Lollipop 0.6 Cola 0.3
Bob Sweets 0.1 N/A N/A
Abe Sweets 0.1 N/A N/A

通过 unique 过滤 df3 没有帮助,因为排列确实是唯一的。

在我的场景中,我 100% 确定加入 df1 的每个后续 df 正好有 3 行,这与 df1$'Col A' 中存在“Tom”的原始行数相匹配。

在我的真实场景中,这个 join/merge 将部署在一个循环中,其中 Col A 中的每个条目也恰好出现 3 次。所以在后面的循环中,它会对“Abe”和“Bob”做同样的事情。

bind_cols() 不够通用,因为这些列可能已经在之前的循环中创建(即 Col DCol E 已经由 Tom 的循环创建,其中 N/As 表示 Abe 和 Bob 的行)。在这种情况下,我只希望估算值,而不是创建新列(如果使用相同的列名会进一步冲突)。

是否有 script/function/package 来实现我的意图?转换为 tibbles 也很好。也许有一些条件可以将 _join/mergebind_cols?

结合起来

问题是 *_join 不知道要加入哪一行,所以它加入了所有三行。鉴于您的预期输出,您希望 Tom 行按照它们在数据框中出现的相同顺序加入。您可以添加一个 rowid 列,这将让 *_join 知道您想要将 Tom/1 加入 Tom/1

library(tidyverse)

# data
df1 <- read.table(text = "
ColA    ColB    ColC
Tom IceCream    0.2
Tom Candy   0.4
Tom Lollipop    0.6
Bob Sweets  0.1
Abe Sweets  0.1", h = T)

df2 <- read.table(text = "
ColA    ColD    ColE
Tom Sweets  0.5
Tom Chocolate   0.2
Tom Cola    0.3", h = T)



# add row ids
df1 <- df1 %>%
  group_by(ColA) %>%
  mutate(rowid = row_number())

df2 <- df2 %>%
  mutate(rowid = row_number())


# join
left_join(df1,df2)
#> Joining, by = c("ColA", "rowid")
#> # A tibble: 5 x 6
#> # Groups:   ColA [3]
#>   ColA  ColB      ColC rowid ColD       ColE
#>   <chr> <chr>    <dbl> <int> <chr>     <dbl>
#> 1 Tom   IceCream   0.2     1 Sweets      0.5
#> 2 Tom   Candy      0.4     2 Chocolate   0.2
#> 3 Tom   Lollipop   0.6     3 Cola        0.3
#> 4 Bob   Sweets     0.1     1 <NA>       NA  
#> 5 Abe   Sweets     0.1     1 <NA>       NA

reprex package (v2.0.0)

于 2021-08-31 创建

分配 rowid 的替代方法是根据 ColA、运行 cbind/bind_colsdf1 进行子集化,然后重新加入 df1.

df1 %>%
  filter(ColA == unique(df2$ColA)) %>%
  bind_cols(df2[,-1]) %>%
  right_join(df1)

#-----------
Joining, by = c("ColA", "ColB", "ColC")
  ColA     ColB ColC      ColD ColE
1  Tom IceCream  0.2    Sweets  0.5
2  Tom    Candy  0.4 Chocolate  0.2
3  Tom Lollipop  0.6      Cola  0.3
4  Bob   Sweets  0.1      <NA>   NA
5  Abe   Sweets  0.1      <NA>   NA