在 dplyr 中,如何按列连接数据框,这些列可能存在也可能不存在?

5

我有两个数据框需要连接。其中,我总是有一个相互的“主”列进行连接,而我有时也可能有另一列数据要进行连接,除了主列之外。

如何指定一个可能的列进行连接?

示例

我用从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可能出现,但不保证出现,这样当它在两个数据中同时出现时,它将成为一个额外的“联接-by”列,否则它将从by参数中忽略?

期望输出

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
@deschen 因为在实际情况中可能会有许多类似的列。 - Emman
1个回答

4
创建一个交集名称的向量。
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

1
太棒了。FYI我将其封装在一个函数中:`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"))` - Emman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接