在 dplyr 中,如何通过可能存在或不存在的列连接数据框?
Posted
技术标签:
【中文标题】在 dplyr 中,如何通过可能存在或不存在的列连接数据框?【英文标题】:In dplyr, how to join dataframes by columns that may or may not exist? 【发布时间】:2021-05-22 22:10:06 【问题描述】:我有两个要加入的数据框架。虽然我总是有一个 main 相互列可以加入,但我有时可能在数据中还有一个我想要加入的列,除了主要的列。
我如何指定一个可能的列来加入?
示例
我用来自mtcars
的两个数据集来演示我的问题。两者都有一个“主”列 (cars
),我将始终加入该列,有时在一个或两个数据集中可能还有另一个相互列 (some_letters
)。
library(tidyverse)
create_df <- function(columns_to_include)
mtcars %>%
rownames_to_column("cars") %>%
select(cars, columns_to_include ) %>%
slice_sample(n = 15) %>%
if (sample(c(TRUE, FALSE), size = 1)) add_column(., some_letters = letters[1:15]) else .
# both dataframes have "some_letters"
set.seed(123)
df_a1 <- create_df(carb)
df_a2 <- create_df(gear)
scenario_a <- inner_join(df_a1, df_a2, by = c("cars", "some_letters"))
scenario_a
#> cars carb some_letters gear
#> 1 Ford Pantera L 4 l 5
# neither dataframe has "some_letters"
set.seed(111)
df_b1 <- create_df(carb)
df_b2 <- create_df(gear)
scenario_b <- inner_join(df_b1, df_b2, by = c("cars", "some_letters"))
#> Error: Join columns must be present in data.
#> x Problem with `some_letters`.
# one dataframe has "some_letters" but the other doesn't
set.seed(737)
df_c1 <- create_df(carb)
df_c2 <- create_df(gear)
scenario_c <- inner_join(df_c1, df_c2, by = c("cars", "some_letters"))
#> Error: Join columns must be present in data.
#> x Problem with `some_letters`.
由reprex package (v0.3.0) 于 2021-02-20 创建
我们可以看到,在scenario_a
中,连接有效,因为df_a1
和df_a2
都包含some_letters
。但是,在scenario_b
中,我们看到连接失败,因为some_letters
不存在(在任一数据中)。同样,scenario_c
显示some_letters
出现在一个数据集中但没有出现在另一个数据集中的情况,因此连接失败。
在加入数据时,我是否可以指定some_letters
是可能的,但不保证会出现,这样当它出现在两个数据中时,它将成为附加的join-by 列,否则它将被@ 忽略987654335@参数?
期望的输出
inner_join(df_b1, df_b2, by = c("cars", "some_letters"))
# as if we joined by `cars` only:
## cars carb gear
## 1 Porsche 914-2 2 5
## 2 Cadillac Fleetwood 4 3
## 3 Pontiac Firebird 2 3
## 4 Datsun 710 1 4
## 5 Merc 240D 2 4
## 6 Chrysler Imperial 4 3
## 7 Hornet 4 Drive 1 3
## 8 Camaro Z28 4 3
【问题讨论】:
您为什么不简单地创建一个 if 条件来检查您想要的列是否在数据集中可用。如果是,则按两列进行连接,如果不是,则仅按第一列进行连接。 @deschen 因为在实际情况下可能有很多这样的列。 【参考方案1】:创建一个包含intersect
ing 名称的向量
library(dplyr)
library(purrr)
nm1 <- reduce(list(names(df_b1), names(df_b2),
c("cars", "some_letters")), intersect)
然后加入
inner_join(df_b1, df_b2, by = nm1)
-输出
# cars carb gear
#1 Porsche 914-2 2 5
#2 Cadillac Fleetwood 4 3
#3 Pontiac Firebird 2 3
#4 Datsun 710 1 4
#5 Merc 240D 2 4
#6 Chrysler Imperial 4 3
#7 Hornet 4 Drive 1 3
#8 Camaro Z28 4 3
【讨论】:
太棒了。仅供参考,我将其包装在一个函数中:my_inner_join <- function(dat_1, dat_2, join_by_cols) intersection_vec <- reduce(list(names(dat_1), names(dat_2), join_by_cols), intersect) inner_join(dat_1, dat_2, by = intersection_vec)
调用 my_inner_join(df_b1, df_b2, join_by_cols = c("cars", "some_letters"))
以上是关于在 dplyr 中,如何通过可能存在或不存在的列连接数据框?的主要内容,如果未能解决你的问题,请参考以下文章
在 c# 中,如何测试/获取/设置可能存在或不存在的注册表项?