【问题标题】:Use dataframe name as suffix when joining several data frames连接多个数据框时使用数据框名称作为后缀
【发布时间】:2021-03-03 17:21:37
【问题描述】:

我需要合并多个具有重复列名的数据框。我正在使用dplyr::left_joinpurrr::reduce 在文件上迭代函数。 dplyr::left_join 的标准行为是为重复的 col 名称添加后缀,但这无助于确定变量来自哪些文件,除非您手头有代码。以下是我的情况的简化示例:

a <- tibble(id = 1:5, var=letters[1:5])
b <- tibble(var=letters[11:15], id=1:5)
c <- tibble(id = 1:5, var=letters[16:20], var2="a")
reduce(list(a,b,c), left_join, by="id")

# A tibble: 5 x 5
     id var.x var.y var   var2 
  <int> <chr> <chr> <chr> <chr>
1     1 a     k     p     a    
2     2 b     l     q     a    
3     3 c     m     r     a    
4     4 d     n     s     a    
5     5 e     o     t     a     

有没有办法使用数据框名称作为后缀,并将后缀强制所有重复的列?我想要的是:

# A tibble: 5 x 5
     id var.a var.b var.c   var2 
  <int> <chr> <chr> <chr>  <chr>
1     1 a     k     p      a    
2     2 b     l     q      a    
3     3 c     m     r      a    
4     4 d     n     s      a    
5     5 e     o     t      a  

left_join 中有一个suffix 选项,但我如何在reduce 中使用它?

【问题讨论】:

    标签: r join dplyr


    【解决方案1】:

    left_join 中的后缀无法工作,因为当一次只作用于两个数据帧时,它不知道哪些列在所有输入数据帧中是唯一的或不唯一的。

    1) 而是在连接之前为所有数据帧中的所有非按列添加后缀。 left_join 行中的 by = "id" 可以省略,因为它将默认为。

    最后,我们删除了唯一出现的没有后缀的列上的后缀;但是,在这种情况下,可能不需要 rmSuffix(删除任何后缀)和 uniq_stem(仅返回其向量参数中其词干是唯一的那些组件)和管道末尾的 rename_with 行。

    如果您不需要最终的 rename_with 和它使用的相关函数,这种方法可能没问题,因为那时它非常简单;否则,最好使用 (2) 以避免在 (1) 中保留某些边缘情况以及在 left_join 之前设置列名的丑陋,只需要在 left_join 之后再次修复它们。

    library(dplyr)
    library(purrr)
    library(tibble)
    
    rmSuffix <- function(x) sub("\\.[^.]*", "", x)
    uniq_stem <- function(x) x[ave(x, rmSuffix(x), FUN = length) == 1]
    
    lst(a, b, c) %>%
      map2(names(.), ~ rename_with(.x, function(x) paste(x, .y, sep = "."), -id)) %>%
      reduce(left_join, by = "id") %>%
      rename_with(rmSuffix, .cols = uniq_stem(names(.)))
    

    给予:

    # A tibble: 5 x 5
         id var.a var.b var.c var2 
      <int> <chr> <chr> <chr> <chr>
    1     1 a     k     p     a    
    2     2 b     l     q     a    
    3     3 c     m     r     a    
    4     4 d     n     s     a    
    5     5 e     o     t     a   
    

    2) 第二种方法是在 left_join 之前完全处理列表。这消除了与修复 (1) 中的初始重命名相关的所有正则表达式和问题。 add_suffix 有 data.frame 和 list 方法。在后一种情况下,列表必须是数据框的命名列表,并且 exclude 是列名的向量,除了列表的数据框中唯一出现的列名之外,不会为其添加后缀。

    add_suffix <- function(x, ...) UseMethod("add_suffix")
    
    add_suffix.data.frame <- function(x, suffix, exclude = NULL, ...) {
      ok <- !names(x) %in% exclude
      names(x)[ok] <- paste(names(x)[ok], suffix, sep = ".")
      x
    }
    
    add_suffix.list <- function(x, exclude = NULL, ...) {
      nms <- unlist(lapply(x, names))
      exclude2 <- unname(c(nms[ave(nms, nms, FUN = length) == 1], exclude))
      Map(add_suffix, x, names(x), MoreArgs = list(exclude = exclude2))
    }
    
    
    lst(a, b, c) %>%
      add_suffix(exclude = "id") %>%
      reduce(left_join, by = "id")
    

    【讨论】:

    • 谢谢,但这似乎只有在数据帧具有相同数量的列并且列具有相同位置时才有效,这在我的简化示例中就是这种情况,但在实际情况中并非如此。我修改了示例以使其更清楚,并要求提供通用解决方案。
    • 已更改以反映问题示例中的更改。
    • 太棒了!作为最后的润色:如果变量名包含一个点,此代码将无法按预期工作,我认为“stemify”函数中的正则表达式应该是\.[^\.]*$。如果这是正确的,您介意将其添加到您的代码中以便我接受解决方案吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2021-09-25
    • 2019-06-03
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多