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_join
、right_join
或 merge
与 by = "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_join
、left_join
或 merge
与 by = "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 D
和 Col E
已经由 Tom 的循环创建,其中 N/A
s 表示 Abe 和 Bob 的行)。在这种情况下,我只希望估算值,而不是创建新列(如果使用相同的列名会进一步冲突)。
是否有 script/function/package 来实现我的意图?转换为 tibbles 也很好。也许有一些条件可以将 _join
/merge
与 bind_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_cols
对 df1
进行子集化,然后重新加入 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
考虑 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_join
、right_join
或 merge
与 by = "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_join
、left_join
或 merge
与 by = "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 D
和 Col E
已经由 Tom 的循环创建,其中 N/A
s 表示 Abe 和 Bob 的行)。在这种情况下,我只希望估算值,而不是创建新列(如果使用相同的列名会进一步冲突)。
是否有 script/function/package 来实现我的意图?转换为 tibbles 也很好。也许有一些条件可以将 _join
/merge
与 bind_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_cols
对 df1
进行子集化,然后重新加入 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