2016-04-28 8 views
-1

Я суммирую данные в таблице данных. Group, где мне нужно взять одно значение переменной в группе. Я хочу, чтобы это значение было режимом группы. Я думаю, что это должен быть режим, потому что обычно группа состоит из 8 строк, и у нее будет 2 строки по одному значению, а остальные 6 или около того будут другим значением.R - Функция быстрого режима для использования в data.table [, lapply (.SD, Mode), by =.()]

Вот упрощенный пример, с:

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

Я хочу это:

key1 2 

У меня были проблемы с использованием стандартной функции режима при условии базовой R, так что я использовал это решение здесь : Most frequent value (mode) by group

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

Он работал отлично по моему небольшому набору тестовых данных, но когда я запускаю его в своем фактическом наборе данных (22 миллиона строк), он просто запускается и запускается и запускается. Все мои другие data.table операции, которые аналогичные работают очень и очень быстро, но я не использую UDF. Это структура моего data.table запроса:

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

Так что я предполагаю, моя проблема в том, что мой UDF действительно замедляет работу, есть ли какие-либо предложения, где я могу достичь той же цели, но получить его сделано намного быстрее?

Спасибо всем!

EDIT: Лучше представление данных:

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") 
+1

На основании этого кода ', lapply (.SD, Mode),. (Key1 = Key1, Key2 = Key2, [...]', ваш фактический 'data.table', кажется, сильно отличается от примера вы включили что-то более представительное (т. е. не двухколоночный объект, а уменьшенная версия ваших реальных данных)? – nrussell

+0

Hi @nrussel, материнская плата моей основной машины потерпела крах.Более выборка данных: 'DT <- Fread (" key1A key2A key3A key4A 2 2 4 с key1A key2A key3A key4A 2 2 4 с key1A key2A key3A key4A 8 8 8 т key1A key2A key3A key4A 2 2 4 с key1B key2B key3B key4B 6 6 6 v key1B key2B key3B key4B 2 2 5 т key1B key2B key3B key4B 2 2 ' И это ожидаемый результат 5 об key1B key2B key3B key4B 2 2 5 V"): 'результат < - fread ("key1A key2A key3A key4A 2 2 4 s key1B key2B key3B key4B 2 2 5 v") ' – Factuary

ответ

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 

Вам необходимо рассмотреть тай-брейк g тщательно. Я мог бы использовать цикл for, чтобы применить это к большему количеству столбцов значений, но вам нужно будет предоставить репрезентативный воспроизводимый пример, если вы хотите, чтобы я попытался это сделать.

Edit:

Frank предоставляет один из вариантов сделать это для нескольких столбцов значений в комментарии:

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

Однако, я считаю, это копии каждого столбца значение, которое может замедлить его слишком много.

+1

Для дополнительных cols' DT [, lapply (.SD, function (x) setDT (list (x = x)) [, .N, by = x] [order (-N)] [1L, x]), by = V1] ', но я не знаю, что это будет быстрее, чем' Mode' (как в комментарии nrussell). – Frank

+0

Спасибо Roland & Frank, я попробую это, когда вы скажете здесь режим, мы все еще используем 'Mode <- function (x) { ux <- unique (x) ux [who.max (таблица (совпадение (x, ux)))] }, что было выше, или мне нужно изменить это? Как предоставить воспроизводимый пример набора данных, который составляет 17 ГБ? – Factuary

+1

@Factuary Roland просто использует режим для маркировки вывода. Стандартный синтаксис R, y'know: 'c (Name = Value)'. Чтобы сделать воспроизводимый пример, подумайте о данных, которые легко воспроизводятся, что иллюстрирует проблему, с которой вы сталкиваетесь; нам не нужны ваши фактические данные и не обязательно все его идиосинкразии. См. Http://stackoverflow.com/a/28481250/ для получения консультаций. – Frank