обзор
Я относительно знаком с data.table
, не так много с dplyr
. Я прочитал несколько dplyr
виньеток и примеров, которые всплыли на SO, и до сих пор мои выводы таковы:
data.table
иdplyr
сопоставимы по скорости, за исключением случаев, когда существует много (то есть> 10-100 КБ) групп, и при некоторых других обстоятельствах (см. контрольные показатели ниже)dplyr
имеет более доступный синтаксисdplyr
тезисы (или воля) потенциальных взаимодействий БД- Есть некоторые незначительные функциональные различия (см. «Примеры / Использование» ниже)
На мой взгляд, 2. не имеет большого веса, потому что я довольно знаком с ним data.table
, хотя я понимаю, что для пользователей, новичков в обоих, это будет большой фактор. Я хотел бы избежать спора, который является более интуитивным, поскольку он не имеет отношения к моему конкретному вопросу, заданному с точки зрения кого-то, с кем уже знаком data.table
. Я также хотел бы избежать дискуссии о том, как «более интуитивный» ведет к более быстрому анализу (конечно, правда, но опять же, не то, что меня больше всего интересует здесь).
Вопрос
То, что я хочу знать, это:
- Существуют ли аналитические задачи, которые намного проще кодировать с тем или иным пакетом для людей, знакомых с этими пакетами (т. Е. Требуется некоторая комбинация нажатий клавиш в сравнении с требуемым уровнем эзотерики, где меньше каждого из них - хорошая вещь).
- Существуют ли аналитические задачи, которые выполняются существенно (т.е. более чем в 2 раза) более эффективно в одном пакете по сравнению с другим.
Один недавний вопрос SO заставил меня задуматься об этом немного больше, потому что до этого момента я не думал dplyr
, что смогу предложить намного больше того, что я уже могу сделать data.table
. Вот dplyr
решение (данные в конце Q):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
Что было намного лучше, чем моя попытка взломать data.table
решение. Тем не менее, хорошие data.table
решения также довольно хороши (спасибо Жан-Роберту, Аруну, и обратите внимание, здесь я предпочел одно утверждение перед строго самым оптимальным решением):
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
Синтаксис для последнего может показаться очень эзотерическим, но на самом деле он довольно прост, если вы привыкли data.table
(то есть не использовать некоторые из более эзотерических приемов).
В идеале я хотел бы увидеть несколько хороших примеров, в которых dplyr
или был бы data.table
значительно более кратким или значительно более эффективным.
Примеры
Применениеdplyr
не допускает сгруппированных операций, которые возвращают произвольное количество строк (из вопроса Эдди , обратите внимание: похоже, что это будет реализовано в dplyr 0.5 , также @beginneR показывает потенциальный обходной путь, используемыйdo
в ответе на вопрос @ eddi).data.table
поддерживает скользящие соединения (спасибо @dholstius), а также соединения с перекрытиемdata.table
внутренне оптимизирует выражение видаDT[col == value]
илиDT[col %in% values]
для скорости через автоматическую индексацию , которая использует бинарный поиск , используя тот же синтаксис базового R. Смотрите здесь для более подробной информации и крошечного теста.dplyr
предлагает стандартные оценочные версии функций (напримерregroup
,summarize_each_
), которые могут упростить программное использованиеdplyr
(обратите внимание, программное использованиеdata.table
определенно возможно, просто требует некоторого тщательного обдумывания, подстановки / цитирования и т. д., по крайней мере, насколько мне известно)
- Я запустил свои собственные тесты и обнаружил, что оба пакета сопоставимы в анализе стиля «разделение и объединение», за исключением случаев, когда существует очень большое количество групп (> 100 КБ), в этот момент
data.table
скорость существенно увеличивается. - @Arun провел несколько тестов для объединений , показав, что он
data.table
масштабируется лучше, чемdplyr
при увеличении количества групп (обновлено с учетом последних улучшений в обоих пакетах и последней версии R). Кроме того, тест при попытке получить уникальные значения имеетdata.table
~ 6 раз быстрее. - (Непроверенный) на
data.table
75% быстрее на больших версиях группы / применить / сортировать и наdplyr
40% быстрее на меньших ( еще один вопрос из комментариев , спасибо Данас). - Мэтт, главный автор
data.table
, имеет протестированные группировка операций наdata.table
,dplyr
и питонpandas
на срок до 2 миллиардов строк (~ 100GB в оперативной памяти) . - Старше тест на 80k групп имеет
data.table
~ 8x быстрее
Данные
Это первый пример, который я показал в разделе вопросов.
dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane",
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob",
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L,
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L,
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager",
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager",
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L,
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id",
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA,
-16L))
dplyr
и data.table
команда, и команда работают над эталонами, так что ответ будет в какой-то момент. № 2 (синтаксис) imO строго ложно, но это явно затрагивает территорию мнений, поэтому я тоже голосую за закрытие.
(d)plyr
имеет меру 0
dplyr
и в plyr
отношении синтаксиса, и в основном это главная причина, почему мне не нравится их синтаксис, это то, что мне нужно выучить слишком много (читай более 1) дополнительных функций (с именами, которые до сих пор не имеет смысла для меня), помните, что они делают, какие аргументы они используют и т. д. Это всегда было огромным препятствием для меня от философии plyr.
.SD
). [серьезно] Я думаю, что это законные конструктивные отличия, которые понравятся разным людям
dplyr
:as.data.table(dat)[, .SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)], by = list(name, job)]