R 替代 full_join、right_join、合并而不增加行?

Lar*_*Cai 1 r dataframe tibble data-wrangling

考虑 2 个 dfs:

df1:

可乐 上校 B 上校
汤姆 冰淇淋 0.2
汤姆 糖果 0.4
汤姆 棒糖 0.6
鲍勃 糖果 0.1
安倍 糖果 0.1

df2:

可乐 寒冷的 科尔
汤姆 糖果 0.5
汤姆 巧克力 0.2
汤姆 可乐 0.3

如果我使用full_join,right_joinmergewith by = "Col A"(with all.y=TRUE),我会将每个“排列”作为自己的行:

df3:

可乐 上校 B 上校 寒冷的 科尔
汤姆 冰淇淋 0.2 糖果 0.5
汤姆 冰淇淋 0.2 巧克力 0.2
汤姆 冰淇淋 0.2 可乐 0.3
汤姆 糖果 0.4 糖果 0.5
汤姆 糖果 0.4 巧克力 0.2
汤姆 糖果 0.4 可乐 0.3
汤姆 棒糖 0.6 糖果 0.5
汤姆 棒糖 0.6 巧克力 0.2
汤姆 棒糖 0.6 可乐 0.3
鲍勃 糖果 0.1 不适用 不适用
安倍 糖果 0.1 不适用 不适用

如果我使用inner_join, left_join, 或mergewith by = "Col A"(没有all.y=TRUE ),除了子集化为仅操作的行之外,我得到的结果与上面相同,例如,将删除包含 Abe 和 Bob 的行:

df4:

可乐 上校 B 上校 寒冷的 科尔
汤姆 冰淇淋 0.2 糖果 0.5
汤姆 冰淇淋 0.2 巧克力 0.2
汤姆 冰淇淋 0.2 可乐 0.3
汤姆 糖果 0.4 糖果 0.5
汤姆 糖果 0.4 巧克力 0.2
汤姆 糖果 0.4 可乐 0.3
汤姆 棒糖 0.6 糖果 0.5
汤姆 棒糖 0.6 巧克力 0.2
汤姆 棒糖 0.6 可乐 0.3

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

df5:

可乐 上校 B 上校 寒冷的 科尔
汤姆 冰淇淋 0.2 糖果 0.5
汤姆 糖果 0.4 巧克力 0.2
汤姆 棒糖 0.6 可乐 0.3
鲍勃 糖果 0.1 不适用 不适用
安倍 糖果 0.1 不适用 不适用

过滤 df3 byunique无济于事,因为排列确实是独一无二的。

在我的场景中,我 100% 确定每个后续 df 加入到 df1 正好有 3 行,这与df1$'Col A'.

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

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

是否有脚本/函数/包来执行我的意图?转换为 tibbles 也很好。也许是将 a _join/merge与 a结合的一些条件bind_cols

nni*_*loc 6

问题是*_join不知道要加入哪一行,所以它加入了所有三行。给定您的预期输出,您希望Tom行以它们在数据框中出现的相同顺序加入。您可以添加rowid列,这将让*_join知道你想加入Tom/1Tom/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
Run Code Online (Sandbox Code Playgroud)

reprex 包( v2.0.0 )于 2021 年 8 月 31 日创建


分配rowids的另一种方法是df1基于ColA,运行cbind/ 的子集bind_cols,然后重新加入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
Run Code Online (Sandbox Code Playgroud)