Улучшение производительности функции split() в R?

У меня есть кадр данных в очень простой форме:

    X Y
    ---
    A 1
    A 2
    B 3
    C 1
    C 3

Мой конечный результат должен быть таким списком:

$`A`
[1] 1 2

$`B`
[1] 3

$`C`
[1] 1 3

Для этой операции я использую функцию split() в R:

k <- split(Y, X)

Это работает просто отлично. Однако, если я хочу применить этот код к фрейму данных, содержащему 22 миллиона строк, включая 10 миллионов групп для X и 387 000 значений для Y, это займет очень много времени. Я попытался использовать открытую версию RRO 8.0 для поддержки MKL. Однако по-прежнему используется только одно ядро. Процессор имеет 64 ГБ оперативной памяти, так что это не должно быть проблемой.

Любые идеи для более умного способа вычислить это?


person Daniel Schultz    schedule 04.12.2014    source источник
comment
Разве эти операции не могут быть выполнены с помощью data.table или dplyr   -  person akrun    schedule 04.12.2014
comment
Я пытался использовать dplyr, но не мог понять, как это сделать. В любом случае dplyr не вернет фрейм данных? Я думаю, что структура списка была бы более удобной для постобработки.   -  person Daniel Schultz    schedule 04.12.2014
comment
Вы можете вернуть столбец в виде списка в data.table, а также в dplyrdo)   -  person akrun    schedule 04.12.2014
comment
Я был бы рад использовать dplyr. В попытке я использовал функции group_by и summarise, но не смог найти лучший способ сделать это.   -  person Daniel Schultz    schedule 04.12.2014
comment
Что вы планируете делать со списком? Может быть, вы можете избежать создания всего этого   -  person talat    schedule 04.12.2014
comment
Я хочу выполнить анализ потребительской корзины с помощью функции apriori из пакета arules.   -  person Daniel Schultz    schedule 04.12.2014
comment
?apriori принимает в качестве входных данных объект транзакций класса или любую структуру данных, которую можно преобразовать в транзакции (например, двоичную матрицу или data.frame). Таким образом, вы, вероятно, могли бы работать без преобразования в список. Однако у меня нет опыта работы с этим пакетом.   -  person talat    schedule 04.12.2014
comment
Удачи. У всех нас одна и та же проблема с split   -  person Rich Scriven    schedule 04.12.2014
comment
@beginneR Я действительно мог бы попробовать.   -  person Daniel Schultz    schedule 05.12.2014
comment
@beginneR Я пытался использовать data.frame, так как apriori не нужен список в меньшем тестовом фрейме данных. Однако результаты не коррелируют на единицу. Когда я использую фрейм данных, команда as находит количество строк как транзакций. Хотя, очевидно, список находит количество групп в качестве транзакций. Второй способ - это то, что я хочу. Я был бы рад избавиться от списка из-за времени, но я не вижу, как это сделать. Первые тесты не были многообещающими.   -  person Daniel Schultz    schedule 05.12.2014


Ответы (2)


Пытаться

 library(data.table)
 DT <- as.data.table(df)
 DT1 <- DT[, list(Y=list(Y)), by=X]
 DT1$Y
 #[[1]]
 #[1] 1 2

 #[[2]]
 #[1] 3

 #[[3]]
 #[1] 1 3

Или используя dplyr

 library(dplyr)
 df1 <-  df %>% 
             group_by(X) %>%
              do(Y=c(.$Y))

 df1$Y
 #[[1]]
 #[1] 1 2

 #[[2]]
 #[1] 3

 #[[3]]
 #[1] 1 3

данные

 df <- structure(list(X = c("A", "A", "B", "C", "C"), Y = c(1L, 2L, 
 3L, 1L, 3L)), .Names = c("X", "Y"), class = "data.frame", row.names = c(NA, 
 -5L))
person akrun    schedule 04.12.2014
comment
Я фанат dplyr, но я заметил, что использование dplyr::do может быть намного медленнее, чем остальная часть dplyr, к сожалению. - person talat; 04.12.2014
comment
@beginneR Спасибо за комментарий. Я думаю, что dplyr не предназначен (в настоящее время) для операций со списками. - person akrun; 04.12.2014
comment
Тогда я попробую использовать data.table. Я еще не работал с пакетом, так как думал, что с точки зрения производительности dplyr и data.table взаимозаменяемы. Мне пока кодирование в dplyr понравилось больше - person Daniel Schultz; 04.12.2014
comment
@DanielSchultz Судя по некоторым тестам, для больших наборов данных data.table быстрее. - person akrun; 04.12.2014
comment
Я сейчас пробую data.table код. dplyrcode сократил время до 3 часов. Посмотрим, что data.table сможет сделать. - person Daniel Schultz; 04.12.2014
comment
@DanielSchultz Спасибо, это будет сравнительный анализ. - person akrun; 04.12.2014
comment
@akrun Итак, я попробовал код data.table. Я запускаю код без ошибки, но новый фрейм данных не появляется. Я запускаю код на тестовом наборе данных, содержащем подвыборку из 200 строк, все работает как надо. Поскольку я не получаю сообщения об ошибке, а код работает с меньшей таблицей данных, я не знаю, что изменить. - person Daniel Schultz; 05.12.2014
comment
@DanielSchultz Вы назначили его новому объекту, как я показал? Я не уверен, что там происходит. Поскольку data.table предназначен для больших наборов данных, это выглядит странно. - person akrun; 05.12.2014
comment
@akrun Я обнаружил еще одну странность: моя переменная в столбце 2 является множителем, а не числовым. Я думал, что это не должно быть проблемой. Однако в подвыборке с 200 строками все векторы столбца 2 одинаковы. Разницы нет. Я не могу представить, как это происходит. Хотя исходная таблица данных выглядит нормально - person Daniel Schultz; 05.12.2014
comment
@DanielSchultz Когда я проверил это на примере df, оказалось, что это factor (после того, как я изменил Y на фактор). str(DT1) Classes ‘data.table’ and 'data.frame': 3 obs. of 2 variables: $ X: chr "A" "B" "C" $ Y:List of 3 ..$ : Factor w/ 3 levels "1","2","3": 1 2 ..$ : Factor w/ 3 levels "1","2","3": 3 ..$ : Factor w/ 3 levels "1","2","3": 1 3 - person akrun; 05.12.2014
comment
@DanielSchultz Я использую R 3.1.2. и data.table_1.9.5 - person akrun; 05.12.2014
comment
@akrun Я использую те же версии - person Daniel Schultz; 05.12.2014
comment
@DanielSchultz Итак, я думаю, этот тип странностей возникает только в полном наборе данных, а не в каком-либо из подмножеств, верно? - person akrun; 05.12.2014
comment
@akrun Если я перекодирую Y, чтобы учесть минимальный пример, я действительно могу воссоздать ошибку: > DT1 X Y 1: A 1,3 2: B 1,3 3: C 1,3 Это явно не то, что мы планировали;) - person Daniel Schultz; 05.12.2014
comment
@akrun Я не получаю никаких результатов для полного набора данных. Странность возникает в подвыборке и в минимальном примере, который я создал для stackoverflow. - person Daniel Schultz; 05.12.2014
comment
@DanielSchultz Я почему-то не мог получить эту ошибку. Я использую версию для разработчиков. - person akrun; 05.12.2014
comment
@DanielSchultz Может быть, вы можете связаться с авторами напрямую или опубликовать новый вопрос с этой странностью, чтобы больше людей изучили его. - person akrun; 05.12.2014
comment
@DanielSchultz Мне очень нравится помогать вам с этим, но без воспроизведения этого я не могу понять, в чем проблема. - person akrun; 05.12.2014

Я нашел элегантное решение, используя аналогичный код из dplyr и/или data.table. Я искал конкатенированные группы в R и нашел этот пост:

Эффективно объединять содержимое символов в одном столбце по группам в R

И на самом деле, он довольно хорошо работает с

dt = data.table(content = sample(letters, 26e6, T), groups = LETTERS)
df = as.data.frame(dt)

system.time(dt[, paste(content, collapse = " "), by = groups])
#   user  system elapsed 
#   5.37    0.06    5.65 

system.time(df %>% group_by(groups) %>% summarise(paste(content, collapse = " ")))
#   user  system elapsed 
#   7.10    0.13    7.67 

Спасибо за вашу помощь

person Daniel Schultz    schedule 09.02.2015