R data.table按组获取N个最频繁的值

R data.table按组获取N个最频繁的值,r,data.table,R,Data.table,比如说,我想为每个购物类别查找前三位最常见的邮政编码。在本例中,类别为住宅、联排别墅和公寓。我有如下事务数据: set.seed(1234) d <- data.table(purch_id = 1:3e6, purch_cat = sample(x = c('home','townhouse','condo'), size = 3e6, replace=TRUE),

比如说,我想为每个购物类别查找前三位最常见的邮政编码。在本例中,类别为住宅、联排别墅和公寓。我有如下事务数据:

set.seed(1234)
d <- data.table(purch_id = 1:3e6,
                purch_cat = sample(x = c('home','townhouse','condo'), 
                                   size = 3e6, replace=TRUE),
                purch_zip = formatC( sample(x = 1e4:9e4, size = 3e6, replace=TRUE), 
                                     width = 5, format = "d", flag = "0") )
set.seed(1234)
d编辑:改进。
我认为你的思路是正确的。但是,您缺少的一个关键功能是函数
frank
,该函数已经过优化,应该可以大大提高代码的速度(在3m行样本数据上几乎同时运行):

一种方法是

d[ , .N, by=.(purch_cat, purch_zip)][
  order(-N), 
  .SD[ N >= unique(N)[3] ]
,by=purch_cat]

    purch_cat purch_zip  N
 1: townhouse     39587 33
 2: townhouse     80365 30
 3: townhouse     37360 30
 4: townhouse     83099 28
 5: townhouse     33518 28
 6: townhouse     59347 28
 7: townhouse     22402 28
 8:     condo     39169 32
 9:     condo     15725 31
10:     condo     75768 30
11:     condo     72023 30
12:      home     71294 30
13:      home     56053 30
14:      home     57971 29
15:      home     77521 29
16:      home     70124 29
17:      home     25302 29
18:      home     65292 29
19:      home     39488 29
20:      home     81754 28
21:      home     43426 28
22:      home     16943 28
23:      home     88978 28
24:      home     43003 28
25:      home     76501 28
    purch_cat purch_zip  N
    purch_cat purch_zip  N
 1: townhouse     39587 33
 2: townhouse     80365 30
 3: townhouse     37360 30
 4:     condo     39169 32
 5:     condo     15725 31
 6:     condo     75768 30
 7:     condo     72023 30
 8:      home     71294 30
 9:      home     56053 30
10:      home     57971 29
11:      home     77521 29
12:      home     70124 29
13:      home     25302 29
14:      home     65292 29
15:      home     39488 29

要实现OP打破平局的规则,可以这样做

d[ , .N, by=.(purch_cat,purch_zip)][
  order(-N),
  .SD[ N >= unique(N)[3] ][
      .N - frank(N, ties.method='max') < 3 ]
, by=purch_cat]

根据@MichaelChirico的回答,这种方法增加了一个
frank
步骤。

@frank实际上似乎是正确的,用于现实世界。。。如果有ties@Frank这只是打破平局的逻辑,但没什么大不了的。我只是想要purch_rank@C8H10N4O2实际上,请参见编辑。您的回答基本正确。
frank()
在下一个版本中也将进行内部优化[以避免
eval()
惩罚](希望)…再次感谢frank--顺便说一句,这似乎是三种解决方案中最快的一种。根据我的基准测试,OP=.555秒,你的是.370秒,@MichaelChirico的是3.5秒。等等——看看他的更新我明白为什么
N>=unique(N)[3]
,但我想我的想法是,如果第一个有五个邮政编码,我就不需要看第六个邮政编码(及其联系,然后是第六个邮政编码及其联系)。我知道我说过我对各种打破僵局的方法持开放态度,但我觉得如果有很多领带的话,其他的方法会更接近我想要的。再次感谢,我从这个(+1)@C8H10N4O2中学到了很多谢谢。我知道你从哪里来,并会更新答案,如果我找到了一种方法,会让你知道(因为我也有兴趣这样做);我只是还没来得及看一看。@C8H10N4O2已更新。事实证明,只需一个额外的步骤,就可以以相同的方式编写。@C8H10N4O2您可以通过限制领带的数量,在计算所有拉链上的
frank
之前,在第二步中进行子集设置,从而加快编写速度。如果有很多拉链将被忽略,这将非常昂贵。非常感谢(+1). 在data.table 1.9.5中,@Frank的速度稍快(330秒对370秒,对我笔记本电脑上的OP.500秒),先发布,可能不那么笨重,但你的教了我一个新功能,所以我接受这个。
    purch_cat purch_zip  N
 1: townhouse     39587 33
 2: townhouse     80365 30
 3: townhouse     37360 30
 4: townhouse     83099 28
 5: townhouse     33518 28
 6: townhouse     59347 28
 7: townhouse     22402 28
 8:     condo     39169 32
 9:     condo     15725 31
10:     condo     75768 30
11:     condo     72023 30
12:      home     71294 30
13:      home     56053 30
14:      home     57971 29
15:      home     77521 29
16:      home     70124 29
17:      home     25302 29
18:      home     65292 29
19:      home     39488 29
20:      home     81754 28
21:      home     43426 28
22:      home     16943 28
23:      home     88978 28
24:      home     43003 28
25:      home     76501 28
    purch_cat purch_zip  N
d[ , .N, by=.(purch_cat,purch_zip)][
  order(-N),
  .SD[ N >= unique(N)[3] ][
      .N - frank(N, ties.method='max') < 3 ]
, by=purch_cat]
    purch_cat purch_zip  N
 1: townhouse     39587 33
 2: townhouse     80365 30
 3: townhouse     37360 30
 4:     condo     39169 32
 5:     condo     15725 31
 6:     condo     75768 30
 7:     condo     72023 30
 8:      home     71294 30
 9:      home     56053 30
10:      home     57971 29
11:      home     77521 29
12:      home     70124 29
13:      home     25302 29
14:      home     65292 29
15:      home     39488 29