【问题标题】:Join dataframes using an OR condition for columns to match by使用 OR 条件连接数据框以匹配列
【发布时间】:2021-07-07 22:15:18
【问题描述】:

假设我们有两个要加入的数据框。 为简单起见,假设两者具有相同的行数,并且一个数据帧中的每一行都必须在另一个数据帧中具有唯一的对应行。 这是此设置的 MWE:

library(dplyr)
df1 <- tibble(id1 = 1:3, x = c("b", "a", "b"), y = c(55, 50, 58), z = c(65, 60, 69))
df2 <- tibble(id2 = 11:13, x = c("a", "b", "b"), y = c(50, 55, 59), z = c(61, 66, 69))

# # A tibble: 3 x 4
#     id1 x         y     z
#   <int> <chr> <dbl> <dbl>
# 1     1 b        55    65
# 2     2 a        50    60
# 3     3 b        58    69
# # A tibble: 3 x 4
#     id2 x         y     z
#   <int> <chr> <dbl> <dbl>
# 1    11 a        50    61
# 2    12 b        55    66
# 3    13 b        59    69

目标是将df1 中的唯一ID 与df2 中唯一但不同的ID 链接起来。我可以利用xyz 列中的组合信息足以唯一标识行的事实来做到这一点。下面详细解释的问题是,如果我们能够通过c("x", "y" OR "z") 之类的方式加入,则在此设置中加入将正常工作。

  • x 列开始,我们有足够的信息将id1 == 2id2==11 联系起来,因为它们具有相同的唯一值(即"a")。但是,仅列 x 不足以容纳其余的对。
  • 在连接中使用列y 允许我们将id1 == 1id2==12 链接起来。但是,y 列(除了x)将(正确地)不匹配id1 == 3id2==13,因为它们具有不同的y 值。
  • 在连接中使用z 列允许我将id1 == 3id2==13 链接,但现在我们遇到了与以前相同的问题,现在将id1 == 1id2==12 链接:它们的@987654346 不同@ 值。此外,如果我们通过z 加入,那么我们会破坏id1 == 2id2==11 的链接(尽管没有这个额外的怪癖,该示例仍然可以工作)。

因此,问题是除了在x 上严格匹配之外,是否有一种好的和/或简洁的方法可以在yz 列上使用OR 条件连接这两个数据帧。类似的东西

full_join(df1, df2, by = c("x", "y" OR "z"))

到目前为止,我的尝试涉及一系列连接和其他操作,但是阅读起来非常麻烦(这使得它容易出错),而且对于足够大的数据来说可能太慢了。我愿意更正这种方法,或者被告知这是这样做的唯一方法(尽管我真的希望不是)。

left_join(df1, df2, by = c("x", "y"), suffix = c("1", "2")) %>% 
  left_join(df2, by = c("x", "z1" = "z"), suffix = c("1", "2")) %>% 
  rowwise() %>% 
  mutate(id2 = sum(id21, id22, na.rm = T)) %>% 
  select(id1, id2)

# # A tibble: 3 x 2
# # Rowwise: 
#     id1   id2
#   <int> <int>
# 1     1    12
# 2     2    11
# 3     3    13

【问题讨论】:

    标签: r join dplyr


    【解决方案1】:

    您可以使用 tidyr 将两个 data.frames 转换为长格式。

    library(tidyr)
    library(dplyr)
    
    df2_2 <- df2 %>% 
      pivot_longer(c(y, z))
    
    df1_1 <- df1 %>% 
      pivot_longer(c(y, z))
    

    接下来,您将 inner_join 两个以 x 为轴的 data.frames 和新的 value 列恢复为宽格式。所以

    df1_1  %>% 
      inner_join(df2_2, by=c("x", "value")) %>% 
      pivot_wider(names_from="name.x") %>% 
      select(-name.y)
    

    返回

    # A tibble: 3 x 5
        id1 x       id2     y     z
      <int> <chr> <int> <dbl> <dbl>
    1     1 b        12    55    NA
    2     2 a        11    50    NA
    3     3 b        13    NA    69
    

    df1_1  %>% 
      inner_join(df2_2, by=c("x", "value")) %>% 
      pivot_wider(names_from="name.x") %>% 
      select(id1, id2)
    

    为您提供所需的输出

    # A tibble: 3 x 2
        id1   id2
      <int> <int>
    1     1    12
    2     2    11
    3     3    13
    

    如果yz 属于同一类型,这可以正常工作。如果它们是不同的类型(例如一个是字符,另一个是双精度),您必须将它们转换为通用格式,以便 pivot_longer 工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 2016-04-05
      • 2020-04-09
      • 2021-08-18
      • 2012-12-31
      相关资源
      最近更新 更多