Немає прямолінійної / простої відповіді, оскільки філософія обох цих пакетів різниться в певних аспектах. Тож деяких компромісів не уникнути. Ось деякі проблеми, які можуть вам знадобитися для вирішення / розгляду.
Операції, що включають i
(== filter()
та slice()
в dplyr)
Припустимо, DT
скажімо з 10 стовпців. Розглянемо ці вирази data.table:
DT[a > 1, .N]
DT[a > 1, mean(b), by=.(c, d)]
(1) дає кількість рядків у DT
стовпці де a > 1
. (2) повертає mean(b)
згруповані за c,d
тим самим виразом, що i
і (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()
колонки apriori:
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). Вираз в 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 ви можете агрегувати під час приєднання, і це простіше зрозуміти та ефективно використовувати пам’ять, оскільки проміжний результат об’єднання ніколи не матеріалізується. Перегляньте цей пост для прикладу. Ви не можете (наразі?) Зробити це, використовуючи синтаксис data.table / data.frame dplyr.
Функція рухомого з’єднання 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
методи для таблиць даних, але таблиця даних також має свої власні порівнянні методи