Почему rbindlist "лучше", чем rbind?
Я просматриваю документацию data.table
а также заметил из некоторых разговоров здесь на так что rbindlist
должен быть лучше, чем rbind
.
Я хотел бы знать, почему rbindlist
лучше, чем rbind
и в каких сценариях rbindlist
действительно превосходит rbind
?
есть ли какие-либо преимущества с точки зрения использования памяти?
2 ответов
rbindlist
является оптимизированной версией do.call(rbind, list(...))
, который известен тем, что медленный при использовании rbind.data.frame
где это действительно excel
некоторые вопросы, которые показывают, где 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.данные.frame rownames может расстраивать
rbindlist
справлюсь с lists
data.frames
и data.tables
, и возвращает данные.стол без rownames
вы можете попасть в путаницу имен строк, используя 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
' s use.names
функцию v1.9.3
. Набор данных состоит из 10000 данных.кадров, каждый размером 10*500.
NB: этот тест был обновлен, чтобы включить сравнение к dplyr
' s bind_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 секунды. По сравнению с базовым решением, это 14x быстрее, и 18x быстрее, чем dplyr
'S версии.