为什么rbindlist比rbind“更好”?
我正在通过data.table
文档,也注意到从这里的一些对话, rbindlist
应该比rbind
更好。
我想知道为什么rbindlist
比rbind
更好,在哪种情况下rbindlist
真的超越rbind
?
在内存使用方面有没有优势?
rbindlist
是do.call(rbind, list(...))
一个优化版本,在使用rbind.data.frame
它在哪里真的很好
一些显示rbindlist
闪耀的问题
按行快速vector化data.frames列表的合并
使用do.call和ldply将长列表data.frames(〜100万)转换为单个data.frame时遇到问题
这些基准显示了它的速度。
rbind.data.frame很慢,这是有原因的
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))) ## ab ## 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))) ## ab ## 1: 1 2 ## 2: 2 3 ## 3: 1 2 ## 4: 2 3
rbindlist的一些其他限制
过去由于一个已经被修复的错误,过去一直在努力处理factors
:
rbindlist两个data.tables,其中一个具有因子,另一个具有字符types ( Bug#2650 )
它有重复的列名称的问题
请参阅警告消息:在rbindlist(allargs):由强制引入的NAs:data.table中可能的错误? ( 错误#2384 )
rbind.data.frame rownames会令人沮丧
rbindlist
可以处理lists
data.frames
和data.tables
,并将返回一个data.table没有rownames
你可以使用do.call(rbind, list(...))
看看do.call(rbind, list(...))
如何避免在do.call中使用rbind时重命名行?
内存效率
在内存方面, rbindlist
是在C
实现的,所以是内存高效的,它使用setattr
通过引用来设置属性
rbind.data.frame
是在R
中实现的,它做了很多的分配,并且使用attr<-
(和class<-
和rownames<-
所有这些都将(在内部)创build创build的data.frame的副本。
在v1.9.2
, rbindlist
已经发展了很多,实现了许多function,包括:
- 在绑定时select列的最高
SEXPTYPE
– 在closuresFR#2456和Bug#4981的v1.9.2
实现。- 正确处理
factor
列 – 首先在v1.8.10
实现,closuresBug#2650,并在v1.9.2
仔细扩展到绑定sorting因子,closuresFR#4856和Bug#5019 。
此外,在v1.9.2
, rbind.data.table
也获得了一个fill
参数,允许通过填充缺失列进行绑定,在R中实现。
现在在v1.9.3
,这些现有function还有更多的改进:
rbindlist
获得一个参数use.names
,默认情况下为FALSE
以实现向后兼容性。rbindlist
也获得了一个参数fill
,为了向后兼容,默认情况下也是FALSE
。- 这些function都是用C语言实现的,并且在添加function的同时,仔细书写,不会影响速度。
- 由于
rbindlist
现在可以按名称匹配并填充缺失的列,rbindlist
现在只需调用rbindlist
。 唯一的区别是对于rbind.data.table
,默认情况下use.names=TRUE
,以便向后兼容。
rbind.data.frame
主要是由于拷贝(也指出了@mnel),可以避免的(通过移动到C)减慢了一些。 我认为这不是唯一的原因。 当每个data.frame有很多列时,检查/匹配rbind.data.frame
列名的rbind.data.frame
也会变慢,并且有很多这样的data.frames要绑定(如下面的基准所示)。
然而,这个rbindlist
缺less某些特征(比如检查因子级别或匹配的名字)对rbind.data.frame
权重很小(或没有)。 这是因为他们在C中谨慎实现,针对速度和内存进行了优化。
这是一个基准,它突出了在按列名进行匹配时的高效绑定,以及使用rbindlist
的use.names
特性。 数据集由10000个大小为10 * 500的dataframe组成。
require(data.table) 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 # 3.419 0.278 3.718 system.time(ans2 <- rbindlist(ll, use.names=TRUE)) # user system elapsed # 5.311 0.471 5.914 system.time(ans3 <- do.call("rbind", ll)) # user system elapsed # 1097.895 1209.823 2438.452 identical(ans2, setDT(ans3)) # [1] TRUE
在没有检查名字的情况下,对列进行绑定的时间仅为3.7秒,因为检查列名和绑定的时间只需要1.2秒。 与基本解决scheme相比,这个速度快了400倍。