【问题标题】:Filter out rows of group that don't fit criteria [duplicate]过滤掉不符合条件的组行[重复]
【发布时间】:2023-03-15 22:09:01
【问题描述】:

这是用于此问题的代码:

set.seed(1337)
myDT <- data.table(Key1 = sample(letters, 500, replace = TRUE),
                   Key2 = sample(LETTERS[1:5], 500, TRUE),
                   Data = sample(1:26, 500, replace = TRUE))
setkey(myDT, Key1, Key2)
# showing what myDT looks like
> myDT
     Key1 Key2 Data
  1:    a    A    6
  2:    a    A    3
  3:    a    B    2
  4:    a    B   20
  5:    a    B   13
 ---               
496:    z    D   23
497:    z    E    3
498:    z    E   18
499:    z    E   11
500:    z    E    2

我想配对 myDT 以仅获取每个 Key1、Key2 对的最大数据值。例如。 (使用 (Key1,Key2) 表示一对)对于 (a,A) 我想去掉 Data 为 3 的行并保留 Data 为 6 的行。对于 (z,E) 我想只保留 Data 为 18 的行。

在输入这个问题时,我想到了一个解决方案(我将在下面发布),但请帮助我知道你将如何解决这个问题。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我的回答

    myDT[order(-Data), head(.SD, 1), by = .(Key1, Key2)]
    # if you are on 1.9.6 or lower use this one
    myDT[order(-Data), .SD[1], by = .(Key1, Key2)]
    

    或来自 cmets

    unique(myDT[order(-Data)], by = c("Key1", "Key2"))
    

    50M 行的基准测试。

    library(dplyr)
    library(data.table)
    library(microbenchmark)
    set.seed(1337)
    n = 5e7
    myDT <- data.table(Key1 = sample(letters, n, replace = TRUE),
                       Key2 = sample(LETTERS[1:5], n, TRUE),
                       Data = sample(1:26, n, replace = TRUE))
    setkey(myDT, Key1, Key2)
    
    microbenchmark(times = 10L,
                   CathG = myDT[, .SD[which.max(Data)], by = .(Key1, Key2)],
                   jangorecki = myDT[order(-Data), head(.SD, 1), by = .(Key1, Key2)],
                   jangorecki.keeporder = myDT[order(-Data), head(.SD, 1), keyby = .(Key1, Key2)],
                   nist = myDT %>% group_by(Key1,Key2) %>% summarise(Data = max(Data)),
                   David = unique(myDT[order(-Data)], by = c("Key1", "Key2")))
    
    #Unit: milliseconds
    #                 expr       min        lq      mean   median        uq       max neval
    #                CathG  659.6150  689.3035  733.9177  739.795  780.0075  811.1456    10
    #           jangorecki 2844.7565 3026.3385 3089.6764 3097.332 3219.1951 3343.9919    10
    # jangorecki.keeporder 2935.3733 3194.1606 3232.9297 3214.581 3308.0735 3411.4319    10
    #                 nist  803.1921  844.5002 1011.7878 1007.755 1188.6127 1228.3869    10
    #                David 3410.4853 3501.5918 3590.2382 3590.190 3652.8091 3803.9038    10
    

    之前发布的小数据基准测试显示了截然不同的结果,所以我想说它在很大程度上取决于数据,不仅是数量,而且还取决于基数(唯一值的计数)——在某些情况下甚至可能更多。

    【讨论】:

      【解决方案2】:

      基于this Q 的另一种方法是:

       myDT[, .SD[which.max(Data)], by = .(Key1, Key2)]
       #    Key1 Key2 Data
       # 1:    a    A    6
       # 2:    a    B   20
       # 3:    a    C   25
       # 4:    a    E    7
       # 5:    b    A   25
       #---               
      #119:    z    A   23
      #120:    z    B   26
      #121:    z    C   24
      #122:    z    D   25
      #123:    z    E   18
      

      【讨论】:

      • 这看起来不错,但我无法让它终止。我的数据有 120k 行和 64 列。拉出三列,做这个操作,然后将它们合并回来是否明智?
      • 我使用了您获得的链接来使用 Matt Dowle 的高效实现。为什么这个版本效率低?
      • @jks612 [ on .SD 增加了一些开销,请参阅我的答案和基准
      • @jks612 你试过myDT[myDT[,.I[which.max(Data)],by=.(Key1,Key2)][['V1']]] 吗?您应该选择 jangorecki 的答案,它既好又高效! :-)
      【解决方案3】:

      使用 dplyr 解决问题的更快更好的方法

      myDT %>% group_by(Key1,Key2) %>% summarise(Data = max(Data))
      

      要保留数据中的所有现有列,您可以使用slice 而不是summarise

      myDT %>% group_by(Key1,Key2) %>% slice(which.max(Data))
      

      请注意,这将准确地返回每组 1 行,如果出现平局,它将是 Data 列的第一个最大行。

      【讨论】:

      • 如何合并任何缺失的列? myDT
      • @jks612,请参阅有关如何保留其他列的更新答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 2020-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多