Ответ 1
Нет простого или простого ответа, потому что философия обоих этих пакетов отличается в некоторых аспектах. Поэтому некоторые компромиссы неизбежны. Вот некоторые из проблем, которые могут возникнуть для решения/рассмотрения.
Операции с i
(== filter()
и slice()
в dplyr)
Предположим DT
, скажем, 10 столбцов. Рассмотрим эти выражения data.table:
DT[a > 1, .N] ## --- (1)
DT[a > 1, mean(b), by=.(c, d)] ## --- (2)
(1) дает количество строк в DT
, где находится столбец a > 1
. (2) возвращает mean(b)
, сгруппированное по c,d
для того же выражения в i
как (1).
Обычно используемые выражения dplyr
:
DT %>% filter(a > 1) %>% summarise(n()) ## --- (3)
DT %>% filter(a > 1) %>% group_by(c, d) %>% summarise(mean(b)) ## --- (4)
Очевидно, что коды данных. Кроме того, они также более эффективны с точки зрения памяти 1. Зачем? Поскольку в обоих (3) и (4), filter()
сначала возвращает строки для всех 10 столбцов, когда в (3) нам просто нужно количество строк, а в (4) нам нужны только столбцы b, c, d
для последовательного операции. Чтобы преодолеть это, мы должны select()
столбцы apriori:
DT %>% select(a) %>% filter(a > 1) %>% summarise(n()) ## --- (5)
DT %>% select(a,b,c,d) %>% filter(a > 1) %>% group_by(c,d) %>% summarise(mean(b)) ## --- (6)
Необходимо выделить важное философское различие между двумя пакетами:
В
data.table
нам нравится держать эти связанные операции вместе, и это позволяет смотреть наj-expression
(из одного и того же вызова функции) и понимать, что нет необходимости в каких-либо столбцах в (1). Выражение в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 полностью копирует всю таблицу данных внутри, чтобы добавить новый столбец. @BrodieG уже упомянул об этом в своем ответе.
Но глубокую копию можно заменить мелкой копией, когда FR # 617. Также уместно: dplyr: FR # 614. Обратите внимание, что все же, измененный вами столб всегда будет скопирован (следовательно, медленнее или меньше памяти). Невозможно обновить столбцы по ссылке.
Другие функции
-
В data.table вы можете объединиться при объединении, и это более прямолинейно понять и эффективно использовать память, поскольку результат промежуточного соединения никогда не материализуется. Например, этот пост. Вы не можете (на данный момент?) Сделать это, используя синтаксис dplyr data.table/data.frame.
-
data.table функция roll joinings не поддерживается в синтаксисе 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 заключается в том, что она также обеспечивает интерфейс к базам данных с использованием того же синтаксиса, который не содержит данных. момент.
Итак, вам придется взвесить эти (и, возможно, другие моменты) и решить, основываясь на том, приемлемы ли эти компромиссы для вас.
НТН
(1) Обратите внимание, что эффективность памяти напрямую влияет на скорость (особенно по мере увеличения данных), поскольку узкое место в большинстве случаев перемещает данные из основной памяти в кеш (и максимально использует данные в кеше) уменьшить промахи в кэше - чтобы уменьшить доступ к основной памяти). Не вдаваясь в подробности здесь.