Answers:
rbindlist
是的优化版本do.call(rbind, list(...))
,使用时速度较慢rbind.data.frame
一些问题可以显示出哪里rbindlist
发光
使用do.call和ldply将一长串data.frames(〜1百万)转换为单个data.frames时出现问题
这些基准测试显示了测试速度。
rbind.data.frame
进行大量检查,并按名称匹配。(即rbind.data.frame将考虑以下事实,即列的顺序可能不同,并按名称匹配),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
由于已修复了一个错误,因此过去常常难以应对factors
:
rbindlist两个data.tables,其中一个具有因数,另一个具有一列的字符类型(错误#2650)
列名重复有问题
请参阅 警告消息:在rbindlist(allargs)中:强制引入的NA:在data.table中可能存在错误?(错误#2384)
rbindlist
可以处理lists
data.frames
和data.tables
,并且将返回不带行名的data.table
您可以使用do.call(rbind, list(...))
see 混淆行名
在rbindlist
中实现内存方面C
,因此内存效率高,它用于setattr
通过引用设置属性
rbind.data.frame
在中实现R
,它会进行大量分配,并且会使用attr<-
(class<-
并且rownames<-
所有这些都将(内部)创建所创建data.frame的副本。
DF = data.frame(a=1:3); .Internal(inspect(DF)); tracemem(DF); attr(DF,"test") <- "hello"; .Internal(inspect(DF))
。
rbind.data.frame
具有特殊的“劫持”逻辑-当其第一个参数为时data.table
,它会调用.rbind.data.table
,这会进行一点检查,然后在rbindlist
内部调用。因此,如果您已经有data.table
要绑定的对象,则rbind
和之间的性能差异可能很小rbindlist
。
rbindlist
它现在可以按名称匹配(use.names=TRUE
),还可以填充缺少的列(fill=TRUE
)。我已经更新了这个,这个和这个帖子。您介意编辑此文件吗?如果可以,可以吗?两种方法对我来说都很好。
dplyr::rbind_list
也非常相似
通过v1.9.2
,rbindlist
已经发展了很多,实现了许多功能,包括:
SEXPTYPE
在绑定时选择最高的列-在v1.9.2
关闭FR#2456和Bug#4981中实现。factor
正确处理列-首先在v1.8.10
关闭Bug#2650时实现,然后扩展为绑定在v1.9.2
关闭FR#4856和Bug#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
当每个data.frame中有很多列并且要绑定很多此类data.frame时也可能会变慢(如下面的基准所示)。
但是,rbindlist
缺少某些功能(例如检查因子水平或匹配名称)对它的影响很小(或没有),因此比快rbind.data.frame
。这是因为它们是用C精心实现的,并且针对速度和内存进行了优化。
这里有一个基准,突出了高效的结合,同时通过列名的匹配,以及使用rbindlist
的use.names
功能v1.9.3
。数据集由10000个数据帧组成,每个数据帧的大小为10 * 500。
注意:这个测试已经更新到包括比较dplyr
的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秒。与基本解决方案相比,它的速度快了14倍,比dplyr
的版本快18倍。
attr<-
,class<-
(我认为)rownames<-
全部修改到位。