【问题标题】:Merge rows with similar information合并具有相似信息的行
【发布时间】:2019-05-16 14:01:58
【问题描述】:

我有几行的数据框,我需要合并具有相同 ID 的行。

a=read.csv("a.csv")
view(a)

ID  Value1  Value2  Value3  Value4  Value5  Value6
1076    2940    NA  NA  2   NA  NA
1076    2940    1   A-  NA  302 549
1109    2940    NA  NA  3   NA  NA
1109    2940    NA  A-  NA  700 150

我需要这样的结果

ID  Value1  Value2  Value3  Value4  Value5  Value6
1076    2940    1   A-  2   302 549
1109    2940    NA  A-  3   700 150                     

我已经查看了类似问题的答案 (Merging rows with shared information)。但我在结果中遇到了错误。

library(dplyr)
f <- function(x) {
  x <- na.omit(x)
  if (length(x) > 0) paste(x,collapse='-') else NA
}
a_merge <- a %>% group_by(ID)%>%summarise_all(list(f))

但我收到以下错误

Error: Column `Value2` can't promote group 1 to character

请帮忙。

【问题讨论】:

    标签: r merge na


    【解决方案1】:

    当列中的所有值都是NAelse 时,一个选项是使用if/else 创建一个条件以返回NA 在list 中获取unique 非NA 元素

    library(dplyr)
    a %>% 
       group_by(ID) %>%
       summarise_all(list(~ list(if(all(is.na(.))) NA else unique(.[!is.na(.)]))))
    # A tibble: 2 x 7
    #     ID Value1    Value2    Value3    Value4    Value5    Value6   
    #  <int> <list>    <list>    <list>    <list>    <list>    <list>   
    #1  1076 <int [1]> <int [1]> <chr [1]> <int [1]> <int [1]> <int [1]>
    #2  1109 <int [1]> <lgl [1]> <chr [1]> <int [1]> <int [1]> <int [1]>
    

    编辑:

    1) 包裹在list

    2) @Gregor 的评论 - 仅获取 unique 非 NA 元素

    数据

    a <- structure(list(ID = c(1076L, 1076L, 1109L, 1109L), Value1 = c(2940L, 
    2940L, 2940L, 2940L), Value2 = c(NA, 1L, NA, NA), Value3 = c(NA, 
    "A-", NA, "A-"), Value4 = c(2L, NA, 3L, NA), Value5 = c(NA, 302L, 
    NA, 700L), Value6 = c(NA, 549L, NA, 150L)), class = "data.frame", row.names = c(NA, 
    -4L))
    

    【讨论】:

    • 我更喜欢作为列表
    • 根据 OP 的用例为list(unique(.[!is.na(.)])) 添加unique() 可能更可取。
    • @Looper 我认为问题在于list 包装。我改成list(if(all试试吧
    • @Looper 在这种情况下 toString(unique(.[!is.na(.)])) 并删除 list 包装器
    • @Looper a %&gt;% group_by(ID) %&gt;%summarise_all(list(~ if(all(is.na(.))) NA_character_ else toString(unique(.[!is.na(.)]))))
    【解决方案2】:

    这是一个基本的 R 方法,

    setNames(do.call(rbind.data.frame, lapply(split(df, df$ID), function(i) 
                                           sapply(i, function(j) j[!is.na(j)][1]))), names(df))
    
    #    ID Value1 Value2 Value3 Value4 Value5 Value6
    #1 1076   2940      1     A-      2    302    549
    #2 1109   2940   <NA>     A-      3    700    150
    

    【讨论】:

      【解决方案3】:

      如果您使用data.table,您可以避免将所有列转换为列表,而只转换需要的列。

      library(data.table)
      setDT(df)
      
      df[, lapply(.SD, function(x)
                if(length(vals <- unique(x[!is.na(x)])) > 1)
                  list(vals)
                else vals), 
        by = ID]
      
      #      ID Value1 Value2 Value3 Value4 Value5 Value6
      # 1: 1076   2940    2,1     A-      2    302    549
      # 2: 1109   2940            A-      3    700    150
      

      如果您使用的是toString,您可以删除if 并简化操作。这也应该适用于 dplyr。

      df[, lapply(.SD, function(x) toString(unique(x[!is.na(x)]))),
        by = ID]
      # 1: 1076   2940   2, 1     A-      2    302    549
      # 2: 1109   2940            A-      3    700    150
      

      修改后的示例数据(添加了 >1 个不同值的案例)

      df <- fread('
      ID  Value1  Value2  Value3  Value4  Value5  Value6
      1076    2940    2  NA  2   NA  NA
      1076    2940    1   A-  NA  302 549
      1109    2940    NA  NA  3   NA  NA
      1109    2940    NA  A-  NA  700 150
      ')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-26
        • 2017-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-25
        • 2016-11-21
        • 2018-10-23
        相关资源
        最近更新 更多