在 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_a1df_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】:

创建一个包含intersecting 名称的向量

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 &lt;- function(dat_1, dat_2, join_by_cols) intersection_vec &lt;- 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# 中,如何测试/获取/设置可能存在或不存在的注册表项?

带有熊猫数据框的内连接循环,用于可能存在或不存在的各种组合[重复]

在Python中删除可能存在或不存在的字典属性[重复]

MySQL 中可能存在或不存在的引用数据

我的查询需要啥,可能不存在或不存在? [复制]

Excel 怎样去除单元格中的tab分隔符