Почему rbindlist "лучше", чем rbind?
Я просматриваю документацию data.table
а также заметил из некоторых разговоров здесь на так что rbindlist
должен быть лучше, чем rbind
.
Я хотел бы знать, почему rbindlist
лучше, чем rbind
и в каких сценариях rbindlist
действительно превосходит rbind
?
есть ли какие-либо преимущества с точки зрения использования памяти?
2 ответа:
rbindlist
- это оптимизированная версияdo.call(rbind, list(...))
, который известен как медленный при использованииrbind.data.frame
где он действительно преуспевает
некоторые вопросы, которые показывают, где
rbindlist
блескомбыстрое векторизованное слияние списка данных.кадры по строке
эти тесты, которые показывают, как быстро это может быть.
rbind.данные.кадр медленный, по какой-то причине
rbind.data.frame
делает много проверок, и будет соответствовать по имени. (т. е. rbind.данные.фрейм будет учитывать тот факт, что столбцы могут быть в разных порядках и совпадать по имени),rbindlist
не делает такого рода проверки, и присоединится по позициинапример
do.call(rbind, list(data.frame(a = 1:2, b = 2:3), data.frame(b = 1:2, a = 2:3))) ## a b ## 1 1 2 ## 2 2 3 ## 3 2 1 ## 4 3 2 rbindlist(list(data.frame(a = 1:5, b = 2:6), data.frame(b = 1:5, a = 2:6))) ## a b ## 1: 1 2 ## 2: 2 3 ## 3: 1 2 ## 4: 2 3
некоторые другие ограничения rbindlist
это используется к борьбу с
factors
, из-за ошибки, которая с тех пор была исправлена:rbindlist два данных.таблицы, где один имеет фактор, а другой имеет тип символа для столбца (ошибка #2650)
он имеет проблемы с дублированием имен столбцов
посмотреть предупреждение: в rbindlist (allargs): NAs введено принуждение: возможная ошибка в данных.стол? (ошибка #2384)
rbind.данные.фреймовые имена строк могут расстраивать
rbindlist
справлюсь сlists
data.frames
иdata.tables
, и возвращает данные.таблица без имен строквы можете попасть в путаницу имен строк с помощью
do.call(rbind, list(...))
смотритекак избежать переименования строк при использовании rbind внутри do.позвонить?
эффективность памяти
С точки зрения реализуется в
C
, так что память эффективна, он используетsetattr
для установки атрибутов по ссылке
rbind.data.frame
реализуется вR
, он делает много назначения, и используетattr<-
(иclass<-
иrownames<-
все (внутренне) создавать копии созданных данных.рамка.
By
v1.9.2
,rbindlist
эволюционировали совсем немного, реализуя многие функции, в том числе:
- выбор самого высокого
SEXPTYPE
столбцов при привязке-реализовано вv1.9.2
закрытие FR #2456 и ошибка #4981.- обращение
factor
столбцы правильно-сначала реализовано вv1.8.10
закрытие ошибка #2650 и распространяется на привязку приказал факторы, тщательно вv1.9.2
также, закрытие FR #4856 и ошибка #5019.кроме того, в
v1.9.2
,rbind.data.table
получилаfill
аргумент, позволяющий связывать путем заполнения недостающих столбцов, реализован в R.сейчас
v1.9.3
, есть еще больше улучшений на существующие особенности:
rbindlist
получает аргументuse.names
, который по умолчанию составляетFALSE
для обратной совместимости.rbindlist
также получает аргументfill
, который по умолчанию тожеFALSE
для обратной совместимости.- все эти функции реализованы на C и написаны тщательно, чтобы не идти на компромисс в скорости при добавлении функциональных возможностей.
- С
rbindlist
теперь можно сопоставить по именам и заполнить недостающие столбцы,rbind.data.table
просто называетrbindlist
сейчас. Разница только в том, чтоuse.names=TRUE
по умолчаниюrbind.data.table
, для обратной совместимости., что
rbind.data.frame
замедляется совсем немного в основном из-за копий (что также указывает @mnel), которых можно было бы избежать (Перейдя на C). Я думаю, что это не единственная причина. Реализация для проверки / сопоставления имен столбцов вrbind.data.frame
может также замедлиться, когда есть много столбцов на данные.фрейма и таких данных много.фреймы для привязки (как показано в тесте ниже).rbindlist
отсутствие (ed) определенных функций (например, проверка фактора уровни или соответствующие имена) несет очень маленький (или нет) вес к нему быстрее, чемrbind.data.frame
. Это потому, что они были тщательно реализованы в C, оптимизированы для скорости и памяти.вот тест, который подчеркивает эффективную привязку при сопоставлении по именам столбцов, а также с помощью
rbindlist
' suse.names
функциюv1.9.3
. Набор данных состоит из 10000 данных.кадров, каждый размером 10*500.NB: этот тест был обновлен, чтобы включить сравнение к
dplyr
' sbind_rows
library(data.table) # 1.11.5, 2018-06-02 00:09:06 UTC library(dplyr) # 0.7.5.9000, 2018-06-12 01:41:40 UTC set.seed(1L) names = paste0("V", 1:500) cols = 500L foo <- function() { data = as.data.frame(setDT(lapply(1:cols, function(x) sample(10)))) setnames(data, sample(names)) } n = 10e3L ll = vector("list", n) for (i in 1:n) { .Call("Csetlistelt", ll, i, foo()) } system.time(ans1 <- rbindlist(ll)) # user system elapsed # 1.226 0.070 1.296 system.time(ans2 <- rbindlist(ll, use.names=TRUE)) # user system elapsed # 2.635 0.129 2.772 system.time(ans3 <- do.call("rbind", ll)) # user system elapsed # 36.932 1.628 38.594 system.time(ans4 <- bind_rows(ll)) # user system elapsed # 48.754 0.384 49.224 identical(ans2, setDT(ans3)) # [1] TRUE identical(ans2, setDT(ans4)) # [1] TRUE
привязка столбцов как таковых без проверки имен заняла всего 1,3, где проверка имен столбцов и привязка соответственно заняла всего 1,5 секунды больше. По сравнению с базовым решением, это в 14 раз быстрее, и в 18 раз быстрее, чем
dplyr
'S версии.