我正在寻找一种方法,使 dplyr'r full_join 将“by”列中的 NA 视为连接的通配符,即 NA 将匹配其他数据帧的相应列中的任何值并连接相应的行。
示例:我在 R 中有几个 data.frames,定义了某些产品特征,其中一些取决于更细粒度的特征,其他仅取决于高级产品类别:
x = data.frame(class = c("A", "B", "B", "C"), flags = c(NA, "individual", "group", NA), interest = c(0.04, 0.03, 0.02, 0.05));x
y = data.frame(class = c("A", "A", "B", "B", "C"), flags = c("individual", "group", "individual", "group", NA), costs = c(0.05, 0.025, 0.03, 0.02, 0.01));y
> x
class flags interest
1 A <NA> 0.04
2 B individual 0.03
3 B group 0.02
4 C <NA> 0.05
> y
class flags costs
1 A individual 0.050
2 A group 0.025
3 B individual 0.030
4 B group 0.020
5 C <NA> 0.010
现在我想将这两个连接起来创建一个产品特性表,但我希望“flags”列中的 NA 与另一个 data.frame 的 flags 列中的任何值匹配,从而产生以下联合 data.frame :
> expected
class flags interest costs
1 A individual 0.04 0.050
2 A group 0.04 0.025
3 B individual 0.03 0.030
4 B group 0.02 0.020
5 C <NA> 0.05 0.010
不幸的是,full_join仅通过精确的字符串匹配进行匹配,因此flags列中的 不会匹配其他数据帧的flags列的任何值(“group”,“partner”,“individual”):
> actual = full_join(x,y, by=c("class","flags"));actual
class flags interest costs
1 A <NA> 0.04 NA
2 B individual 0.03 0.030
3 B group 0.02 0.020
4 C <NA> 0.05 0.010
5 A individual NA 0.050
6 A group NA 0.025
如何使 full_join 将 NA 视为匹配任何字符串(而不是仅匹配其他 NA)?
您只能在
class
列上加入,然后过滤:
library(dplyr)
x |>
full_join(y, by = "class", relationship = "many-to-many") |>
filter(flags.x == flags.y | is.na(flags.x) | is.na(flags.y)) |>
mutate(flags = coalesce(flags.x, flags.y)) |>
select(class, flags, interest, costs)
# class flags interest costs
# 1 A individual 0.04 0.050
# 2 A group 0.04 0.025
# 3 B individual 0.03 0.030
# 4 B group 0.02 0.020
# 5 C <NA> 0.05 0.010
我想知道您是否可以通过加入非
NA
列来尝试不同的方法。例如,每行 split
您的 data.frame,然后选择不是 NA
的列,并使用它们与第二个 data.frame 联接。对于 class
“A”,其中 NA
为 flags
,它将仅基于 class
进行连接;而对于class
“B”,它将同时加入class
和flags
。
library(tidyverse)
x %>%
split(seq(nrow(.))) %>%
map_dfr(~.x %>%
select_if(!is.na(.)) %>%
inner_join(y, .))
输出
class flags costs interest
1 A individual 0.050 0.04
2 A group 0.025 0.04
3 B individual 0.030 0.03
4 B group 0.020 0.02
5 C <NA> 0.010 0.05