Performance R中merge.data.frame()的更快实现
假设Performance R中merge.data.frame()的更快实现,performance,r,dataframe,Performance,R,Dataframe,假设a和b是两个数据帧。目标是编写一个函数 f(a,b)以与merge相同的方式生成合并数据帧 merge(a,b,all=TRUE)就可以了,那就是用NAs填充a或b中缺少的变量。(问题是merge()似乎非常慢。) 这可以按如下方式完成(伪代码): 然后将所有内容包装在数据框中 下面是一个“幼稚”的实现: merge.datasets1 <- function(a, b) { a.fill <- rep(NA, nrow(a)) b.fill <- rep(NA,
a
和b
是两个数据帧。目标是编写一个函数
f(a,b)
以与merge相同的方式生成合并数据帧
merge(a,b,all=TRUE)
就可以了,那就是用NAs填充a
或b
中缺少的变量。(问题是merge()
似乎非常慢。)
这可以按如下方式完成(伪代码):
然后将所有内容包装在数据框中
下面是一个“幼稚”的实现:
merge.datasets1 <- function(a, b) {
a.fill <- rep(NA, nrow(a))
b.fill <- rep(NA, nrow(b))
a.fill.factor <- as.factor(a.fill)
b.fill.factor <- as.factor(b.fill)
out <- list()
for (v in union(names(a), names(b))) {
if (!v %in% names(a)) {
b.srcvar <- b[[v]]
if (is.factor(b.srcvar))
a.srcvar <- a.fill.factor
else
a.srcvar <- a.fill
} else {
a.srcvar <- a[[v]]
if (v %in% names(b))
b.srcvar <- b[[v]]
else if (is.factor(a.srcvar))
b.srcvar <- b.fill.factor
else
b.srcvar <- b.fill
}
out[[v]] <- unlist(list(a.srcvar, b.srcvar),
recursive=FALSE, use.names=FALSE)
}
data.frame(out)
}
merge.datasets1事实上,您根本没有尝试复制merge(a,b,all=TRUE)
,因为您没有尝试在任何列上进行合并。相反,您只是简单地堆叠数据,在不存在列的地方填充NA
# note that this is not what you want/
dim(merge(sample.datasets[[1]], sample.datasets[[2]], all = T))
[1] 314 5
merge(a,b,all=TRUE)
速度较慢的原因是它默认通过名称的交集进行合并。如果您转换为data.tables
,则merge.data.table
方法的速度非常快,但对于您的测试数据,它将在每次成功合并时创建一个指数级增长的数据集(而不是您希望的7500乘5)
一个简单的解决方案是使用plyr
包中的rbind.fill
library(plyr)
system.time({.x <- Reduce(rbind.fill, sample.datasets)})
## user system elapsed
## 0.16 0.00 0.15
# which is almost identical to
system.time(.old <- Reduce(merge.datasets1, sample.datasets))
## user system elapsed
## 0.14 0.00 0.14
花费在Reduce
的管理费用上的大部分时间,而rbind.fill
并不需要。事实上,您根本没有尝试复制合并(a,b,all=TRUE)
,因为您没有尝试在任何列上进行合并。相反,您只是简单地堆叠数据,在不存在列的地方填充NA
# note that this is not what you want/
dim(merge(sample.datasets[[1]], sample.datasets[[2]], all = T))
[1] 314 5
merge(a,b,all=TRUE)
速度较慢的原因是它默认通过名称的交集进行合并。如果您转换为data.tables
,则merge.data.table
方法的速度非常快,但对于您的测试数据,它将在每次成功合并时创建一个指数级增长的数据集(而不是您希望的7500乘5)
一个简单的解决方案是使用plyr
包中的rbind.fill
library(plyr)
system.time({.x <- Reduce(rbind.fill, sample.datasets)})
## user system elapsed
## 0.16 0.00 0.15
# which is almost identical to
system.time(.old <- Reduce(merge.datasets1, sample.datasets))
## user system elapsed
## 0.14 0.00 0.14
花费在Reduce
开销上的大部分时间,这rbind.fill
不需要。使用数据。table
。因为循环本身并不慢,如果合理使用,特别是在预分配内存的情况下,不要在循环中扩展对象,等等。@JoshuaUlrichdata.table
不起作用,因为它的merge
方法在生成的数据中不包含非公共变量。table.你看过了吗:我愿意打赌有一种方法可以处理数据。table
。使用数据。table
。因为循环本身并不慢,如果您合理地使用它们,特别是在预先分配内存的情况下,不要在循环中扩展对象,等等。@JoshuaUlrichdata.table
不起作用,因为它的merge
方法在结果data.table中不包含非公共变量。你看过这个了吗:我愿意打赌,有一种方法可以处理data.table
。
library(plyr)
system.time({.x <- Reduce(rbind.fill, sample.datasets)})
## user system elapsed
## 0.16 0.00 0.15
# which is almost identical to
system.time(.old <- Reduce(merge.datasets1, sample.datasets))
## user system elapsed
## 0.14 0.00 0.14
system.time(super_fast <- rbind.fill(sample.datasets))
## user system elapsed
## 0.02 0.00 0.02
identical(super_fast, .old)
[1] TRUE