【问题标题】:Joining datasets and coalescing ID columns in R在 R 中连接数据集和合并 ID 列
【发布时间】:2022-08-18 14:59:00
【问题描述】:

我正在尝试加入来自各种数据源的小标题列表。基本上,我有一个期刊列表,我正在尝试从其他来源添加一些信息。

这样做的目的之一是在一些也用于连接的列中填写缺失的数据。例如,我有以下两个类似于我的数据结构的数据集。

df1 <- tibble(journal_title = c(NA, 
                           \"Journal of yyy\",
                           \"Journal of zzz\"),
         issn = c(9999, 1234, NA))

df2 <- tibble(journal_title = c(\"Journal of xxx\", NA, \"Journal of zzz\"),
              issn = c(9999, 1234, 8888),
              rank = c(1,2,3))

> df1
# A tibble: 3 × 2
  journal_title   issn
  <chr>          <dbl>
1 NA              9999
2 Journal of yyy  1234
3 Journal of zzz    NA

> df2
# A tibble: 3 × 3
  journal_title   issn  rank
  <chr>          <dbl> <dbl>
1 Journal of xxx  9999     1
2 NA              1234     2
3 Journal of zzz  8888     3

我希望加入这两个数据集并基本上执行左连接,其中 x = df1 和 y = df2,即 df1 是我想从 df2 添加列的主要数据。

但是,如数据所示,有两个 ID 列应该用于连接功能。问题是其中一列中可能有 NA 。因此,使用by = c(\"issn\", \"journal_title\") 不起作用。

因此我想:

  1. 通过两列(issnjournal_title)加入数据集,因为其中之一可能存在 NA。我想将 issn 保留为“第一次尝试”,然后如果 df2 中没有匹配项,则应使用 journal_title

  2. 用两个数据集中的值填写 NA。

    我尝试通过使用 x = issn 和 y = journal_title 合并两列来制作“合成”ID 列。但是,这不起作用,因为在某些情况下它没有考虑到这一点,例如,issnjournal_title 都存在于第一个数据集,而对于相应的 issn,只有 journal_title存在于第二个数据集中。

    我的目标数据如下所示:

    df3 <- tibble(journal_title = c(\"Journal of xxx\", \"Journal of yyy\", \"Journal of zzz\"),
                  issn = c(9999, 1234, 8888),
                  rank = c(1,2,3))
    
    >  df3
    # A tibble: 3 × 3
      journal_title   issn  rank
      <chr>          <dbl> <dbl>
    1 Journal of xxx  9999     1
    2 Journal of yyy  1234     2
    3 Journal of zzz  8888     3
    

    我希望我已经把自己说清楚了,任何帮助都将不胜感激!

    标签: r dplyr


    【解决方案1】:

    看来您不能将多个连接条件与 OR 结合使用期刊标题作为备份加入密钥。而不是两个left_joins 和中间coalesce 作为解决方法,你可以做一个full_join,然后通过对issn 分组来减少你的结果集。

    df1 |> 
      dplyr::full_join(df2, by=c("issn", "journal_title")) |> 
      dplyr::group_by(issn) |> 
      dplyr::summarise(
        rank = na.omit(rank),
        journal_title = na.omit(journal_title)
        )
    
    
    # A tibble: 3 × 3
    # Groups:   issn [3]
       issn  rank journal_title 
      <dbl> <dbl> <chr>         
    1  1234     2 Journal of yyy
    2  8888     3 Journal of zzz
    3  9999     1 Journal of xxx
    

    它适用于您的最小示例。如果您有大量数据,这可能是一种低效的方式,因为您的中间结果比输出大得多。


    我偶然发现了这个blog post,它展示了一个你也可以使用的coalesce_join 函数。这是一个不完美的优雅解决方案,因为您不能将OR 条件与两个连接键一起使用,但您可以通过管道传输两个coalesce_joins,从而产生相同的输出。

    如果你定义了blog post 中的coalesce_join 函数,你可以像这样使用它

    df <- coalesce_join(df1, df2, by = 'issn', join = dplyr::left_join) |>
          coalesce_join(df2, by = 'journal_title', join = dplyr::left_join) 
    

    【讨论】:

      【解决方案2】:

      也许你可以从这里开始。我不知道它是否涵盖了您所有的案例,但它涵盖了您发布的案例:

      library(dplyr)
      
      df2 %>%
        left_join(df1, by ='issn') %>%
        mutate(journal_title = ifelse(is.na(journal_title.x), journal_title.y, journal_title.x)) %>%
        select(journal_title, issn, rank)
      
      # A tibble: 3 x 3
        journal_title   issn  rank
        <chr>          <dbl> <dbl>
      1 Journal of xxx  9999     1
      2 Journal of yyy  1234     2
      3 Journal of zzz  8888     3
      

      如果您在df2$issn 中有一些NA 并且issndf1 中,则此解决方案涵盖:

      df2 %>%
        left_join(df1, by ='issn') %>%
        mutate(journal_title = ifelse(is.na(journal_title.x), journal_title.y, journal_title.x)) %>%
        left_join(df1, by = 'journal_title') %>%
        mutate(issn = ifelse(is.na(issn.x), issn.y, issn.x)) %>%
        select(journal_title, issn, rank)
      

      有数据:

      df1 <- tibble(journal_title = c(NA, 
                                      "Journal of yyy",
                                      "Journal of zzz",
                                      "Journal of rrr"),
                    issn = c(9999, 1234, NA,1001))
      
      df2 <- tibble(journal_title = c("Journal of xxx", NA, "Journal of zzz","Journal of rrr"),
                    issn = c(9999, 1234, 8888, NA),
                    rank = c(1,2,3,4))
      
      
      > df1
      # A tibble: 4 x 2
        journal_title   issn
        <chr>          <dbl>
      1 NA              9999
      2 Journal of yyy  1234
      3 Journal of zzz    NA
      4 Journal of rrr  1001
      > df2
      # A tibble: 4 x 3
        journal_title   issn  rank
        <chr>          <dbl> <dbl>
      1 Journal of xxx  9999     1
      2 NA              1234     2
      3 Journal of zzz  8888     3
      4 Journal of rrr    NA     4
      

      【讨论】:

        【解决方案3】:

        bind_rows() 的另一个选项:

        bind_rows(df1, df2) |>
          group_by(issn) |> 
          summarise(
            journal_title = na.omit(journal_title),
            rank          = na.omit(rank)
          )
        #    issn journal_title   rank
        #   <dbl> <chr>          <dbl>
        # 1  1234 Journal of yyy     2
        # 2  8888 Journal of zzz     3
        # 3  9999 Journal of xxx     1
        

        【讨论】:

          猜你喜欢
          • 2018-04-08
          • 1970-01-01
          • 2021-08-10
          • 1970-01-01
          • 2020-12-06
          • 2020-05-28
          • 2018-09-20
          相关资源
          最近更新 更多