R - 快速模式功能,用于data.table [,lapply(.SD,Mode),by =。()]

时间:2016-04-28 13:24:34

标签: r data.table lapply mode bigdata

我在data.table,group by中汇总数据,其中我需要在组中获取变量的单个值。我希望这个值成为组的模式。我认为它需要是模式,因为通常一个组是8行,它将在一个值上有2行,而另外6个行将是另一个值。

以下是一个简化示例:

key1 2
key1 2
key1 2
key1 8
key1 2
key1 2
key1 2
key1 8

我想要这个:

key1 2

我在使用base R提供的标准模式功能时遇到了麻烦,所以我在这里使用了这个解决方案: Most frequent value (mode) by group

Mode <- function(x) {
  ux <- unique(x)
  ux[which.max(tabulate(match(x, ux)))]
}

它在我的小测试数据集上运行得很好,但是当我在我的实际数据集(2200万行)上运行它时,它只运行并运行和运行。我所有相似的其他data.table操作工作得很好而且非常快,但我没有使用UDF。这是我的data.table查询的结构:

ModeCharacterColumns <- ExposureHistory[,lapply(.SD,Mode), .(Key1=Key1, Key2=Key2, ..., key7=key7, key8=key8), .SDcols=('col1','col2','col3', ..., 'col53')]

所以我猜我的问题是我的UDF真的放慢了速度,有没有人有任何建议我可以完成相同的目标但是更快地完成它?

谢谢大家!

修改 更好地表示数据:

DT <- fread("key1A key2A key3A key4A 2 2 4 s
             key1A key2A key3A key4A 2 2 4 s  
             key1A key2A key3A key4A 8 8 8 t
             key1A key2A key3A key4A 2 2 4 s
             key1B key2B key3B key4B 6 6 6 v
             key1B key2B key3B key4B 2 2 5 t
             key1B key2B key3B key4B 2 2 5 v
             key1B key2B key3B key4B 2 2 5 v")

期望的结果:

result <- fread("key1A key2A key3A key4A 2 2 4 s
                 key1B key2B key3B key4B 2 2 5 v")

2 个答案:

答案 0 :(得分:5)

尝试使用data.table将数据制表:

DT <- fread("key1 8
             key1 2
             key1 2
             key1 8
             key1 2
             key1 2
             key1 2
             key1 8")

setkeyv(
  DT[, .N, by = .(V1, V2)], #tabulate
  c("V1", "N") #sort by N
   )[, .(Mode = V2[.N]), by = V1] #most frequent value by V1
#     V1 Mode
#1: key1    2

你需要仔细考虑打破平局。我实际上可能会使用for循环将其应用于更多值列,但如果您希望我尝试这样做,您需要提供具有代表性的可重现示例。

修改

Frank为评论中的多个值列提供了一个选项:

DT[, lapply(.SD, function(x) setDT(list(x = x))[, .N, by=x][order(-N)][1L, x]), by=V1]

但是,我相信这会复制每个值列,这可能会使其减慢太多。

答案 1 :(得分:0)

最快的解决方案是CRAN上现在可用的 collapse 包中的函数fmode。它在C ++中计算分组模式(以及可选的加权模式),速度非常令人满意。语法:

fmode(x, g = NULL, w = NULL, ...)

其中x可以是向量,矩阵,data.frame或dplyr分组的小标题,g是分组向量或分组向量的列表,而w是权重向量。对于混合类型的聚合,函数collap提供了一个整洁的解决方案。通话

collap(data, ~ id1 + id2, FUN = fmean, catFUN = fmode, ...)

通过id1和id2汇总数据,将均值应用于data中的所有数字列,并将模式应用于data中的所有非数字(分类)列。默认情况下,返回的数据具有按原始顺序排序的行和列。该解决方案比 data.table 更快,并且可以进一步自定义collap调用。