【问题标题】:R group by key get max value for multiple columnsR group by key获取多列的最大值
【发布时间】:2018-03-07 19:40:49
【问题描述】:

我想做这样的事情:

How to make a unique in R by column A and keep the row with maximum value in column B

除了我的data.table 有一个键列和多个值列。所以说我有以下内容:

   a b c
1: 1 1 1
2: 1 2 1
3: 1 2 2
4: 2 1 1
5: 2 2 5
6: 2 3 3
7: 3 1 4
8: 3 2 1

如果键是列a,我希望为每个唯一的a 返回最大b 的行,如果有多个唯一的最大值b,则获取最大的行c 等多个列。所以结果应该是:

   a b c
1: 1 2 2
2: 2 3 3
3: 3 2 1

我还希望对任意数量的列执行此操作。因此,如果我的 data.table 有 20 列,我希望按从左到右的顺序应用 max 函数。

【问题讨论】:

  • 是的,抱歉,我修好了。
  • 好的,谢谢。我猜某处有骗子,但DT[order(b,c), .SD[.N], by=a] 有效。
  • 酷,有没有一种方法可以对任意数量的列进行通用处理?这仅在我知道列是什么并且可以按名称调用它们的情况下才有效。但我正在尝试编写一个通用函数来执行此操作。
  • 嗯,有cols = c("b","c"); setorderv(DT, cols); DT[, .SD[.N], by=a],尽管这实际上会修改您的数据。我找不到骗子,而且我的想法(排序)似乎效率很低。也许其他人会有一个想法。顺便说一句,DT[, .SD[.N], by=a] 的替代品是 unique(DT, by="a", fromLast=TRUE),如果它是您的关键列,您可以写 key(DT) 代替“a”。

标签: r data.table


【解决方案1】:

这是一个建议的 data.table 解决方案。您可能要考虑使用data.table::frankv,如下所示:

DT[, .SD[frankv(.SD, ties.method="first")[.N],], by=a]

frankv 返回订单。然后[.N] 将占据最大排名。然后将.SD[ 子集添加到该特定行。

如果您的较大数据集失败,请告诉我。

【讨论】:

    【解决方案2】:

    要使此功能适用于任意数量的列,可能的dplyr 解决方案是使用arrange_all

    df <- data.frame(a = c(1,1,1,2,2,2,3,3), b = c(1,2,2,1,2,3,1,2),
                     c = c(1,1,2,1,5,3,4,1))
    
    df %>% group_by(a) %>% arrange_all() %>% filter(row_number() == n())
    
    # A tibble: 3 x 3
    # Groups:   a [3]
    #       a     b     c
    # 1     1     2     2
    # 2     2     3     3
    # 3     3     2     1
    

    【讨论】:

      【解决方案3】:

      使用mutate_at 可以为任意数量的列实现通用解决方案。在下面的示例中,c("a","b","c") 是任意列。

      library(dplyr)
      df %>% arrange_at(.vars = vars(c("a","b","c"))) %>%
        mutate(changed = ifelse(a != lead(a), TRUE, FALSE)) %>%
        filter(is.na(changed) | changed ) %>%
        select(-changed)
      
        a b c
      1 1 2 2
      2 2 3 3
      3 3 2 1
      

      另一个选项可以使用maxdplyr,如下所示。该方法是首先在a 上使用group_by,然后过滤maxb 值。 ab 上的再次 group_by 并过滤 max 值为 c 的行。

      library(dplyr)
      
      df %>% group_by(a) %>%
        filter(b == max(b)) %>%
        group_by(a, b) %>%
        filter(c == max(c))
      
      
      
      # Groups: a, b [3]
      #      a     b     c
      #  <int> <int> <int>
      #1     1     2     2
      #2     2     3     3
      #3     3     2     1
      

      数据

      df <- read.table(text = "a b c
      1: 1 1 1
      2: 1 2 1
      3: 1 2 2
      4: 2 1 1
      5: 2 2 5
      6: 2 3 3
      7: 3 1 4
      8: 3 2 1", header = TRUE, stringsAsFactors = FALSE)
      

      【讨论】:

        【解决方案4】:
        dat <- data.frame(a = c(1,1,1,2,2,2,3,3),
                          b = c(1,2,2,1,2,3,1,2),
                          c = c(1,1,2,1,5,3,4,1))
        
        library(sqldf)
        sqldf("with d as (select * from 'dat' group by a order by b, c desc) select * from d order by a")
        
          a b c
        1 1 2 2
        2 2 3 3
        3 3 2 1
        

        【讨论】:

          猜你喜欢
          • 2022-01-07
          • 2020-06-24
          • 2016-07-02
          • 1970-01-01
          • 1970-01-01
          • 2015-08-20
          • 2016-06-08
          • 2018-10-22
          • 1970-01-01
          相关资源
          最近更新 更多