【问题标题】:How to join tables with multiple primary keys in R (efficiently)?如何(有效地)在 R 中连接具有多个主键的表?
【发布时间】:2021-02-05 07:14:06
【问题描述】:

我对 R 中 dplyr 包中的连接有一个小问题。我有 2 个(大)数据框,我想加入。它们有多个共同的列,但一个就足以加入它们。现在我做这样的事情:

tab1 <- data.frame(id= c("a", "b", "c", "d"),
                   name = c("Mike", "Anna", "John", "Edward"),
                   score = c(10, 20, 30, 20)
tab2 <- data.frame(id= c("a", "b", "c", "d"),
                   name = c("Mike", "Anna", "John", "Edward"),
                   color = c("red", "blue", "blue", "orange")
dplyr::left_join(x, y)

这个解决方案没问题,但是您可以看到连接使用idname 作为键,即使我们不需要两者。我担心的是,由于我使用更大的数据框并且我必须通过多次迭代来做到这一点,所以使用所有同名列会花费无用的时间。

我当然可以指定by = id,但是left_join 将保留name.x 和name.y。

所以我有两个问题:

  1. 使用多个键(例如 20 个键)的连接是否比使用一个键的连接花费更多时间?
  2. 如果答案是肯定的,是否有一种简单的方法来指定一个键并从一个表中删除其他重复的列?

我希望我的问题很清楚,请不要犹豫,要求精确,非常感谢!

【问题讨论】:

    标签: r join dplyr tidyverse


    【解决方案1】:

    关于你的第二个问题。您可以使用suffix 为重复的列添加后缀,以便在连接后轻松删除它们。

    为了回答您的第一个问题,我们可以对不同的选项进行基准测试。由于您关心效率,我还将 dplyr::left_join 与使用 merge 的基本 R 方法进行比较,这为我们提供了四种选择

    1. left_join 按所有键列
    2. left_join 一键+删除重复项
    3. merge 所有关键列
    4. merge 一键+删除重复项

    根据我对您的示例数据的基准测试,left_join 按所有键都比按一个键加入并在之后消除重复项要快。但是,如果您关心效率,我建议您查看merge

    library(dplyr)
    
    tab1 <- data.frame(
      id = c("a", "b", "c", "d"),
      name = c("Mike", "Anna", "John", "Edward"),
      score = c(10, 20, 30, 20)
    )
    tab2 <- data.frame(
      id = c("a", "b", "c", "d"),
      name = c("Mike", "Anna", "John", "Edward"),
      color = c("red", "blue", "blue", "orange")
    )
    dplyr::left_join(tab1, tab2)
    #> Joining, by = c("id", "name")
    #>   id   name score  color
    #> 1  a   Mike    10    red
    #> 2  b   Anna    20   blue
    #> 3  c   John    30   blue
    #> 4  d Edward    20 orange
    
    f1 <- function() left_join(tab1, tab2) 
    f2 <- function() { 
      left_join(tab1, tab2, by = "id", suffix = c("", "_drop")) %>% 
        select(-ends_with("_drop")) 
    }
    f3 <- function() merge(tab1, tab2, by = c("id", "name"), all.x = TRUE)
    f4 <- function() { 
      x <- merge(tab1, tab2, by = "id", all.x = TRUE, suffix = c("", "_drop"))
      x[, names(x)[!grepl("_drop$", names(x))]] 
    }
    
    microbenchmark::microbenchmark(f1(), f2(), f3(), f4())
    
    #> Unit: microseconds
    #>  expr      min        lq      mean   median       uq       max neval cld
    #>  f1() 1574.201 1755.9010 2141.5060 1971.501 2303.651  6831.900   100  b 
    #>  f2() 2861.602 3040.8505 3841.6990 3264.551 3920.701 17639.802   100   c
    #>  f3()  471.801  527.6515  657.6511  588.501  702.851  2607.201   100 a  
    #>  f4()  395.800  442.3005  583.3340  491.801  590.751  3824.800   100 a
    

    【讨论】:

    • 非常感谢,这个真的好用又清晰。看来merge确实效率更高,所以我会考虑使用它。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多