代码之家  ›  专栏  ›  技术社区  ›  C8H10N4O2

在data.table中按组计数快速前n位

  •  1
  • C8H10N4O2  · 技术社区  · 7 年前

    我想知道 frank 按组计数其外观的子组。

    例如,我有属于段和具有邮政编码的客户。我想知道每个部分最常见的3个邮政编码。

    library(data.table)
    set.seed(123)
    n <- 1e6
    df <- data.table( cust_id = 1:n,
                      cust_segment = sample(LETTERS, size=n, replace=T),
                      cust_postal = sample(as.character(5e4:7e4),size=n, replace=T)
                     )
    

    这个链条(在 dcast() 下面)生成 期望输出 但需要两次通过,第一次按分组进行计数,第二次按分组对计数进行排序。

    dcast(
      df[,.(.N),
         by = .(cust_segment, cust_postal)
         ][,.(cust_postal,
              postal_rank = frankv(x=N, order=-1, ties.method = 'first')
         ), keyby=cust_segment
         ][postal_rank<=3],
      cust_segment ~ paste0('postcode_rank_',postal_rank), value.var = 'cust_postal' 
    )
    # desired output:
    # cust_segment postcode_rank_1 postcode_rank_2 postcode_rank_3
    #            A           51274           64588           59212
    #            B           63590           69477           50380
    #            C           60619           66249           53494 ...etc...
    

    这是最好的方法,还是有一个单一的方法?

    1 回复  |  直到 7 年前
        1
  •  1
  •   phiver    7 年前

    forder frankv keyby by

    df[, .N, 
       keyby = .(cust_segment, cust_postal)
       ][order(-N), r := rowid(cust_segment)
         ][r <= 3, dcast(.SD, cust_segment ~ r, value.var ="cust_postal")]
    
        cust_segment     1     2     3
     1:            A 51274 53440 55754
     2:            B 63590 69477 50380
     3:            C 60619 66249 52122
     4:            D 68107 50824 59305
     5:            E 51832 65249 52366
     6:            F 51401 55410 65046
    

    library(microbenchmark)
    
    microbenchmark(C8H10N4O2 = dcast(
                                    df[,.(.N),
                                       by = .(cust_segment, cust_postal)
                                       ][,.(cust_postal,
                                            postal_rank = frankv(x=N, order=-1, ties.method = 'first')
                                       ), keyby=cust_segment
                                       ][postal_rank<=3],
                                    cust_segment ~ paste0('postcode_rank_',postal_rank), value.var = 'cust_postal' 
                                  ),
                  frank = df[, .N, 
                             keyby = .(cust_segment, cust_postal)
                             ][order(-N), r := rowid(cust_segment)
                               ][r <= 3, dcast(.SD, cust_segment ~ r, value.var ="cust_postal")])
    Unit: milliseconds
         expr      min       lq     mean   median       uq      max neval
    C8H10N4O2 136.3318 140.8096 156.2095 145.6099 170.4862 205.8457   100
        frank 102.2789 110.0140 118.2148 112.6940 119.2105 192.2464   100