Нет однозначного / простого ответа, потому что философия обоих этих пакетов различается в определенных аспектах. Так что некоторые компромиссы неизбежны. Вот некоторые из проблем, которые вам, возможно, придется решить / рассмотреть.
Операции с участием i
(== filter()
и slice()
в dplyr)
Допустим, DT
например, 10 столбцов. Рассмотрим эти выражения data.table:
DT[a > 1, .N]
DT[a > 1, mean(b), by=.(c, d)]
(1) дает количество строк в DT
столбце where a > 1
. (2) возвращает mean(b)
сгруппированные по c,d
для того же выражения в i
as (1).
Обычно используемые dplyr
выражения:
DT %>% filter(a > 1) %>% summarise(n())
DT %>% filter(a > 1) %>% group_by(c, d) %>% summarise(mean(b))
Очевидно, что коды data.table короче. Кроме того, они более эффективны с точки зрения памяти 1 . Зачем? Поскольку и в (3), и в (4) сначала filter()
возвращает строки для всех 10 столбцов , тогда как в (3) нам просто нужно количество строк, а в (4) нам просто нужны столбцы b, c, d
для последовательных операций. Чтобы преодолеть это, мы должны select()
априори столбцы:
DT %>% select(a) %>% filter(a > 1) %>% summarise(n())
DT %>% select(a,b,c,d) %>% filter(a > 1) %>% group_by(c,d) %>% summarise(mean(b))
Важно подчеркнуть основное философское различие между двумя пакетами:
В data.table
, нам нравится хранить эти связанные операции вместе, и это позволяет смотреть на j-expression
(из одного и того же вызова функции) и понимать, что нет необходимости в каких-либо столбцах в (1). Выражение in i
вычисляется и .N
представляет собой просто сумму того логического вектора, который дает количество строк; все подмножество никогда не реализуется. В (2) b,c,d
в подмножестве материализуется только столбец , остальные столбцы игнорируются.
Но dplyr
философия заключается в том, чтобы функция хорошо выполняла только одну вещь . Нет (по крайней мере, в настоящее время) способа узнать, filter()
нужны ли для операции все те столбцы, которые мы отфильтровали. Вам нужно думать наперед, если вы хотите эффективно выполнять такие задачи. Я лично считаю, что в данном случае это противоречит интуиции.
Обратите внимание, что в (5) и (6) мы по-прежнему подмножество столбцов, a
которые нам не нужны. Но я не знаю, как этого избежать. Если бы у filter()
функции был аргумент для выбора возвращаемых столбцов, мы могли бы избежать этой проблемы, но тогда функция не будет выполнять только одну задачу (что также является выбором дизайна dplyr).
Подзадача по ссылке
dplyr никогда не будет обновляться по ссылке. Это еще одно огромное (философское) различие между двумя пакетами.
Например, в data.table вы можете:
DT[a %in% some_vals, a := NA]
который обновляет столбец a
по ссылке только для тех строк, которые удовлетворяют условию. На данный момент dplyr глубоко копирует всю таблицу data.table внутри, чтобы добавить новый столбец. @BrodieG уже упоминал об этом в своем ответе.
Но глубокая копия может быть заменена мелкой копией при реализации FR # 617 . Также актуально: dplyr: FR # 614 . Обратите внимание, что изменяемый столбец всегда будет скопирован (поэтому он будет работать медленнее / с меньшим потреблением памяти). Обновить столбцы по ссылке не будет.
Прочие функции
В data.table вы можете агрегировать при объединении, и это более понятно для понимания и эффективно с точки зрения памяти, поскольку промежуточный результат соединения никогда не материализуется. Посмотрите этот пост для примера. Вы не можете (в настоящий момент?) Сделать это, используя синтаксис dplyr data.table / data.frame.
Функция скользящих соединений data.table также не поддерживается в синтаксисе dplyr.
Недавно мы реализовали перекрывающиеся соединения в data.table для соединения по диапазонам интервалов ( вот пример ), которые foverlaps()
на данный момент являются отдельной функцией и поэтому могут использоваться с операторами конвейера (magrittr / pipeR? - сам никогда не пробовал).
Но в конечном итоге наша цель - интегрировать его, [.data.table
чтобы мы могли использовать другие функции, такие как группировка, агрегирование при присоединении и т. Д., Которые будут иметь те же ограничения, что описаны выше.
Начиная с 1.9.4, data.table реализует автоматическое индексирование с использованием вторичных ключей для быстрого двоичного поиска на основе подмножеств с обычным синтаксисом R. Пример: DT[x == 1]
и DT[x %in% some_vals]
автоматически создаст индекс при первом запуске, который затем будет использоваться для последовательных подмножеств из одного столбца в быстрое подмножество с использованием двоичного поиска. Эта функция будет развиваться и дальше. Проверьте эту суть, чтобы получить краткий обзор этой функции.
От способа filter()
реализуется для data.tables, не воспользоваться этой функцией.
Особенностью dplyr является то, что он также предоставляет интерфейс для баз данных с использованием того же синтаксиса, которого нет в data.table на данный момент.
Итак, вам придется взвесить эти (и, возможно, другие моменты) и решить, исходя из того, приемлемы ли для вас эти компромиссы.
HTH
(1) Обратите внимание, что эффективность использования памяти напрямую влияет на скорость (особенно при увеличении объема данных), поскольку узким местом в большинстве случаев является перемещение данных из основной памяти в кеш (и максимальное использование данных в кеше - уменьшите количество промахов в кеше). - чтобы уменьшить доступ к основной памяти). Не будем вдаваться в подробности.
dplyr
методы для таблиц данных, но в таблице данных также есть свои собственные сопоставимые методы