【问题标题】:How to merge rows by grouping and only keep highest value in R如何通过分组合并行并仅在R中保留最高值
【发布时间】:2020-05-22 20:06:46
【问题描述】:

假设如下数据框:

dfX <- data.frame('a' = c('A', 'A', 'B', 'B', 'B', 'C', 'C', 'D', 'D', 'D'),
              'b' = c('c2', 'c2', 'c8', 'c8', 'c4', 'c7', 'c7', 'c9', 'c9','c9'),
              'c' = c('f34', 'f34', 'm92', 'm92', 'm92', 'g22', 'g22', 'i41', 'i41', 'i41'),
              'd' = c('Check', 'Check', 'Check', 'Check', 'UnCheck', 'Check', 'Check', 'Check', 'Check','Check'),
              'val1' = c(54, '', 37, '', '', 51, '', 74, '', ''),
              'val2' = c('', 59, '', 87, 84, '', 62, '', 27, 85))

dfX
    a   b   c    d       val1  val2
1   A1  c2  f34  Check   54 
2   A1  c2  f34  Check         59
3   A2  c8  m92  Check   37 
4   A2  c8  m92  Check         87
5   A2  c4  m92  UnCheck       84
6   A3  c7  g22  Check   51 
7   A3  c7  g22  Check         62
8   A4  c9  i41  Check   74 
9   A4  c9  i41  Check         27
10  A4  c9  i41  Check         85

我想合并列val1val2 按列a, b, c 的等效值对它们进行分组,但是如果列d 显示'Uncheck',则应从结果数据框中删除该行. 最重要的是,如果每组的列中有多个值(例如行A4),则应仅保留重复列的最大值

到目前为止,我的目标是 dplyr 是这样的:(This post 作为源)

FuncX <- function(x) x[x != '']

dfY <- dfX %>%
  group_by(a,b,c) %>%
  summarise_each(funs(FuncX))

但是添加d 列和如果该列标记'Unchecked',那么它应该被删除的上述条件,我找不到解决方法。也未能仅将 A4 行的 max() 值作为输出

想要的输出应该是这样的:

dfY
    a   b   c    d       val1  val2
1   A   c2  f34  Check   54    59
2   B   c8  m92  Check   37    87
3   C   c7  g22  Check   51    62
4   D   c9  i41  Check   74    85

【问题讨论】:

    标签: r dplyr grouping


    【解决方案1】:

    我们需要转换为数字来获得max。 'val1'、'val2' 是 character 类(注意:我们在 data.frame 构造中默认使用 R 4.0.0 其中 stringsAsFactors = FALSE。如果 R 版本 stringsAFactors = TRUE by默认然后下面的as.numeric(.)应该改成as.numeric(as.character(.)))

    library(dplyr)
    dfX %>%
        filter(d == 'Check') %>% 
        group_by(a, b, c, d) %>%
        summarise_at(vars(starts_with('val')), ~ max(as.numeric(.), na.rm = TRUE))
    # A tibble: 4 x 6
    # Groups:   a, b, c [4]
    #  a     b     c     d      val1  val2
    #  <chr> <chr> <chr> <chr> <dbl> <dbl>
    #1 A     c2    f34   Check    54    59
    #2 B     c8    m92   Check    37    87
    #3 C     c7    g22   Check    51    62
    #4 D     c9    i41   Check    74    85
    

    或者在新版dplyr中加上summarise/across

    dfX %>%
     filter(d == 'Check') %>% 
     group_by(a, b, c, d) %>% 
     summarise(across(starts_with('val'), ~ max(as.numeric(.), na.rm = TRUE)))
    

    base R中,我们可以使用aggregate

    dfX[c('val1', 'val2')] <- lapply(dfX[c('val1', 'val2')], as.numeric)
    aggregate(. ~ a + b + c+ d, dfX,subset = d == 'Check', max,
          na.rm = TRUE, na.action = NULL)
    

    或者正如@Onyambu 建议的那样,. 也可以在~ 的右侧以选择其余列作为分组列

    aggregate(cbind(val1, val2) ~ ., dfX,subset = d == 'Check', max,
          na.rm = TRUE, na.action = NULL)
    

    【讨论】:

    • 快速回答。你也可以aggregate(cbind(val1.val2)~........)
    【解决方案2】:

    就目前而言,您的 data.frame 有 val1 和 val2 作为因素,我们可以这样做:

    dfX %>% 
    mutate_at(c("val1","val2"),~replace(as.character(.x),.x=="",NA)) %>% 
    filter(d=="Check") %>% 
    group_by(a,b,c,d) %>% 
    summarize_all(~max(as.numeric(.x),na.rm=TRUE))
    
    # A tibble: 4 x 6
    # Groups:   a, b, c [4]
      a     b     c     d     val1  val2 
      <fct> <fct> <fct> <fct> <chr> <chr>
    1 A     c2    f34   Check 54    59   
    2 B     c8    m92   Check 37    87   
    3 C     c7    g22   Check 51    62   
    4 D     c9    i41   Check 74    85 
    

    【讨论】:

      猜你喜欢
      • 2011-03-14
      • 2015-04-17
      • 1970-01-01
      • 1970-01-01
      • 2013-07-01
      • 2022-01-19
      • 2021-12-23
      • 2016-07-31
      • 1970-01-01
      相关资源
      最近更新 更多