【问题标题】:R - Combining dataframe rows on multiple conditionsR - 在多个条件下组合数据框行
【发布时间】:2017-02-22 04:27:14
【问题描述】:

编辑 我有一个如下的数据框:请注意COL1 有重复的条目,COL2 和 COL3 可以按任何顺序排列,即它们可以出现在数据框中其他列之间的任何位置......并且对确切数量没有限制数据框中的列......以后可能还会附加其他列......

COL1 COL2 COL3 COL5 COL6 COL7 ... ... (goes on)
 10  hai    2   15  10    6   ... ...
 10  hai    3   25  20   12   ... ...
 10  pal    1   35  30   18   ... ...
 11  rfm    9   22  32    9   ... ...
  9  rtf    8   34  54   10   ... ...

我还有一个向量如下:

number <- c("first", "last")

我希望输出如下所示:即

  • COL1 应该有唯一的条目(10,11,9)

  • COL2 应该包含它下面的合并条目,没有重复项(hai pal),不应该考虑合并具有不同 COL1 值的唯一行。仅应合并 COL1 值的重复行...并且 COL2 可以出现在数据框中的任何位置(它并不总是第 2 列)

  • COL3 应包含条目的总和 (2+3+1=6)。 应该只计算重复行的总和。重复行是根据 COL1 值识别的……COL3 也可以出现在数据框中的任何位置(它并不总是第 3 列)。

对于COL5COL6COL7(我以后可能会附加许多列...对于这种情况,我只有 3 列没有必要)我需要一段通用代码,这样如果输入从名为“number”的向量中作为“first”给出,需要从所有剩余列的重复行中获取第一个观察值,即第一行值。如果输入是来自名为“number”的向量的“last”,则需要从所有剩余列的重复行中获取最后一个观察值,即最后一行值。

注意:输出应该存储在另一个数据帧中

OUTPUT(如果输入为“第一个”):

COL1    COL2   COL3 COL5 COL6 COL7
10      hai pal 6   15    10    6
11      rfm     9   22    32    9
 9      rtf     8   34    54   10

在上面的输出中:COL5、COL6、COL7 包含重复条目的第一行值

输出(如果输入为“最后一个”):

COL1    COL2   COL3 COL5 COL6 COL7
10      hai pal 6   15    10    6
11      rfm     9   22    32    9
 9      rtf     8   34    54   10

在上面的输出中:COL5、COL6、COL7 包含重复条目的最后一行值

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    用base R试试这个:

    get.df <- function(df, input) {
      cbind.data.frame(COL1=unique(df$COL1), 
                       COL2=paste(unique(df$COL2), collapse=' '),
                       COL3=sum(df$COL3),
                       df[ifelse(input == 'first', 1, nrow(df)),names(df)[-1:-3]])
    }
    
    get.df(df, 'first')
    # COL1    COL2 COL3 COL5 COL6 COL7
    # 1   10 hai pal    6   15   10    6
    
    get.df(df, 'last')
    # COL1    COL2 COL3 COL5 COL6 COL7
    # 3   10 hai pal    6   35   30   18
    

    根据您的新要求,试试这个:

    df <- read.table(text='COL1 COL2 COL3 COL5 COL6 COL7
                     10  hai    2   15  10    6
                     10  hai    3   25  20   12
                     10  pal    1   35  30   18
                     11  rfm    9   22  32    9
                      9  rtf    8   34  54   10', header=TRUE)
    
    get.df <- function(df, input) {
    
      dups <- unique(df[duplicated(df$COL1),]$COL1)
      df.dup <- df[df$COL1 %in% dups,]
      df.nondup <- df[!(df$COL1 %in% dups),]
      rbind(cbind.data.frame(COL1=unique(df.dup$COL1), 
                       COL2=paste(unique(df.dup$COL2), collapse=' '),
                       COL3=sum(df.dup$COL3),
                       df.dup[ifelse(input == 'first', 1, nrow(df.dup)),names(df.dup)[-1:-3]]),
            df.nondup)
    }
    
    number <- c("first", "last")
    
    get.df(df, 'first')
    
    COL1    COL2 COL3 COL5 COL6 COL7
    1   10 hai pal    6   15   10    6
    4   11     rfm    9   22   32    9
    5    9     rtf    8   34   54   10
    
    get.df(df, 'last')
    
    COL1    COL2 COL3 COL5 COL6 COL7
    3   10 hai pal    6   35   30   18
    4   11     rfm    9   22   32    9
    5    9     rtf    8   34   54   10
    

    【讨论】:

    • 我觉得这个答案很有用。而是一个小小的改动。即使 COL1 中存在非重复值,我也需要上述代码才能工作,即我需要仅对输入 df 中的重复行执行上述操作。对于非重复行,我不希望发生任何操作。我已经编辑了问题
    • 您要在输出数据帧中原样返回具有非重复 COL1 值的行还是丢弃它们?
    • match.names(clabs, names(xi)) 中的错误:名称与以前的名称不匹配
    • 它应该可以正常工作,你可以检查你的 df 是否是一个数据框,并且你是否有一些额外的列?还请先使用您提供的示例数据集进行检查。
    【解决方案2】:

    您可以使用dplyr

    这基本上只是我的comment 对您上一个问题的扩展。

    library(dplyr)
    new_df <- df %>% group_by(COL1) %>% 
                     summarise(COL2 = paste0(unique(COL2), collapse = " "), 
                               COL3 = sum(COL3), 
                               COL5 = first(COL5), 
                               COL6 = first(COL6), 
                               COL7 = first(COL7))
    new_df
    #    COL1    COL2     COL3  COL5  COL6  COL7
    #    <int>   <chr>   <int> <int> <int> <int>
    #1    10    hai pal     6    15    10     6
    

    编辑

    您可以使用last 代替dplyr 中的first 进行类似的操作

    如果只有两个选项(第一个,最后一个),您可以使用if 语句检查条件

    if(number == "first") {
         new_df <- df %>% group_by(COL1) %>% 
                          summarise(COL2 = paste0(unique(COL2), collapse = " "), 
                                    COL3 = sum(COL3), 
                                    COL5 = first(COL5), 
                                    COL6 = first(COL6), 
                                    COL7 = first(COL7))
    } else 
    { 
         new_df <- df %>% group_by(COL1) %>% 
                          summarise(COL2 = paste0(unique(COL2), collapse = " "), 
                                    COL3 = sum(COL3), 
                                    COL5 = last(COL5), 
                                    COL6 = last(COL6), 
                                    COL7 = last(COL7))
    }
    

    【讨论】:

      【解决方案3】:

      我们可以使用data.table

      library(data.table)
      setDT(df1)[, .(COL2 = paste(unique(COL2), collapse= " "),
                     COL3 = sum(COL3),
                     COL5 = COL5[1L],
                     COL6 = COL6[1L],
                     COL7 = COL7[1L]), by = COL1]
      #   COL1    COL2 COL3 COL5 COL6 COL7
      #1:   10 hai pal    6   15   10    6
      

      如果我们使用的是data.table的开发版,即v.1.9.7,那么可以简化为

      setDT(df1)[, c(COL2 = paste(unique(COL2), collapse=" "), 
                   COL3 = sum(COL3) ,.SD[1L]), by = COL1, .SDcols=COL5:COL7]
      #    COL1    COL2 COL3 COL5 COL6 COL7
      #1:   10 hai pal    6   15   10    6
      

      如果我们需要最后一行,请使用 .SD[.N] 而不是 .SD[1L]

      setDT(df1)[, c(COL2 = paste(unique(COL2), collapse=" "),  
           COL3 = sum(COL3) ,.SD[.N]), by = COL1, .SDcols=COL5:COL7]
      #   COL1    COL2 COL3 COL5 COL6 COL7
      #1:   10 hai pal    6   35   30   18
      

      data.table的devel版本安装说明为here

      【讨论】:

      • 我无法安装 v1.9.7,因为它在 Rv3.2.1 中不受支持 .... 出现以下错误
      • 包“data.table”不可用(适用于 R 版本 3.2.1)
      • @Rambo 这很奇怪。新的 R 版本是 R 3.3.1。最好更新到新的 R 版本。
      猜你喜欢
      • 2014-03-12
      • 1970-01-01
      • 2021-11-12
      • 2020-02-17
      • 2012-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多