使用 data.table 存储为列表元素的多个数据帧的完全外连接
Posted
技术标签:
【中文标题】使用 data.table 存储为列表元素的多个数据帧的完全外连接【英文标题】:Full outer join of multiple dataframes stored as elements of a list using data.table 【发布时间】:2014-12-28 02:56:06 【问题描述】:我正在尝试使用data.table
对存储为列表元素的多个数据帧进行完全外部连接。我已经使用reshape
包的merge_recurse()
函数成功地做到了这一点,但是对于较大的数据集来说它非常慢,我想通过使用data.table 来加速合并。我不确定 data.table 处理具有多个数据框的列表结构的最佳方式。我也不确定我是否在唯一键上正确编写了 Reduce()
函数,以便对多个数据帧进行完全外部连接。
这是一个小例子:
#Libraries
library("reshape")
library("data.table")
#Specify list of multiple dataframes
filelist <- list(data.frame(x=c(1,1,1,2,2,2,3,3,3), y=c(1,2,3,1,2,3,1,2,3), a=1:9),
data.frame(x=c(1,1,1,2,2,2,3,3,4), y=c(1,2,3,1,2,3,1,2,1), b=seq(from=0, by=5, length.out=9)),
data.frame(x=c(1,1,1,2,2,2,3,3,4), y=c(1,2,3,1,2,3,1,2,2), c=seq(from=0, by=10, length.out=9)))
#Merge with merge_recurse()
listMerged <- merge_recurse(filelist, by=c("x","y"))
#Attempt with data.table
ids <- lapply(filelist, function(x) x[,c("x","y")])
unique_keys <- unique(do.call("rbind", ids))
dt <- data.table(filelist)
setkey(dt, c("x","y")) #error here
Reduce(function(x, y) x[y[J(unique_keys)]], filelist)
这是我的预期输出:
> listMerged
x y a b c
1 1 1 1 0 0
2 1 2 2 5 10
3 1 3 3 10 20
4 2 1 4 15 30
5 2 2 5 20 40
6 2 3 6 25 50
7 3 1 7 30 60
8 3 2 8 35 70
9 3 3 9 NA NA
10 4 1 NA 40 NA
11 4 2 NA NA 80
这是我的资源:
Suggestion to useReduce()
function on data.table
(见答案的最后评论)
Suggestion to use "unique keys" to do full outer join in data.table
【问题讨论】:
【参考方案1】:这对我有用:
library("reshape")
library("data.table")
##
filelist <- list(
data.frame(
x=c(1,1,1,2,2,2,3,3,3),
y=c(1,2,3,1,2,3,1,2,3),
a=1:9),
data.frame(
x=c(1,1,1,2,2,2,3,3,4),
y=c(1,2,3,1,2,3,1,2,1),
b=seq(from=0, by=5, length.out=9)),
data.frame(
x=c(1,1,1,2,2,2,3,3,4),
y=c(1,2,3,1,2,3,1,2,2),
c=seq(from=0, by=10, length.out=9)))
##
## I used copy so that this would
## not modify 'filelist'
dtList <- copy(filelist)
lapply(dtList,setDT)
lapply(dtList,function(x)
setkeyv(x,cols=c("x","y"))
)
##
> Reduce(function(x,y)
merge(x,y,all=T,allow.cartesian=T)
,dtList)
x y a b c
1: 1 1 1 0 0
2: 1 2 2 5 10
3: 1 3 3 10 20
4: 2 1 4 15 30
5: 2 2 5 20 40
6: 2 3 6 25 50
7: 3 1 7 30 60
8: 3 2 8 35 70
9: 3 3 9 NA NA
10: 4 1 NA 40 NA
11: 4 2 NA NA 80
我还注意到您的代码中存在一些问题。 dt <- data.table(filelist)
导致
> dt
filelist
1: <data.frame>
2: <data.frame>
3: <data.frame>
这很可能是您在上面指出的setkey(dt, c("x","y"))
错误的原因。另外,这对你有用吗?
Reduce(function(x, y) x[y[J(unique_keys)]], filelist)
我只是好奇,因为我在尝试运行它时遇到了错误(使用dtList
而不是filelist
)
Error in eval(expr, envir, enclos) : could not find function "J"
我认为这与自 data.table
的 1.8.8 版以来实施的更改有关,@Arun 在 this answer 中对此进行了解释。
【讨论】:
太好了,这完美地解决了我的问题。我对 Reduce() 函数的尝试也对我不起作用。我只需要根据我可以从不同来源拼凑的内容做出明智的猜测。您的代码工作得更好,谢谢! 不客气; FWIW 你的Reduce
函数离你不远了,我只需要做一些小改动。以上是关于使用 data.table 存储为列表元素的多个数据帧的完全外连接的主要内容,如果未能解决你的问题,请参考以下文章
在列表中有效地重复data.table,从循环中的另一个data.table顺序替换具有相同名称的列
已知线性表最多可能有20个元素,存储每个元素需要8字节,存储每个指针需要4字节。当元素个数为( )时使用单链表比使用数组存储此线性表更加节约空间。