例如(但不确定是否最具代表性):
N <- 1e6
d1 <- data.frame(x=sample(N,N), y1=rnorm(N))
d2 <- data.frame(x=sample(N,N), y2=rnorm(N))
这是我到目前为止所得到的:
d <- merge(d1,d2)
# 7.6 sec
library(plyr)
d <- join(d1,d2)
# 2.9 sec
library(data.table)
dt1 <- data.table(d1, key="x")
dt2 <- data.table(d2, key="x")
d <- data.frame( dt1[dt2,list(x,y1,y2=dt2$y2)] )
# 4.9 sec
library(sqldf)
sqldf()
sqldf("create index ix1 on d1(x)")
sqldf("create index ix2 on d2(x)")
d <- sqldf("select * from d1 inner join d2 on d1.x=d2.x")
sqldf()
# 17.4 sec
最佳答案
当第二个数据帧中的每个键值与第一个数据帧中的每个键值对应时,匹配方法就会起作用。如果第二个数据帧中有重复项,则匹配和合并方法不同。当然,Match 的速度更快,因为它没有做太多事情。特别是它从不寻找重复的键。 (代码后继续)
DF1 = data.frame(a = c(1, 1, 2, 2), b = 1:4)
DF2 = data.frame(b = c(1, 2, 3, 3, 4), c = letters[1:5])
merge(DF1, DF2)
b a c
1 1 1 a
2 2 1 b
3 3 2 c
4 3 2 d
5 4 2 e
DF1$c = DF2$c[match(DF1$b, DF2$b)]
DF1$c
[1] a b c e
Levels: a b c d e
> DF1
a b c
1 1 1 a
2 1 2 b
3 2 3 c
4 2 4 e
在问题中发布的 sqldf 代码中,看起来可能在两个表上使用了索引,但实际上,它们被放置在 sql select 运行之前被覆盖的表上,并且部分地,解释了为什么它这么慢。 sqldf 的想法是 R session 中的数据帧构成数据库,而不是 sqlite 中的表。因此,每次代码引用不合格的表名时,它都会在 R 工作区中查找,而不是在 sqlite 的主数据库中查找。因此,显示的 select 语句将 d1 和 d2 从工作区读取到 sqlite 的主数据库中,破坏带有索引的数据库。结果,它执行没有索引的连接。如果您想使用 sqlite 主数据库中的 d1 和 d2 版本,则必须将它们称为 main.d1 和 main.d2,而不是 d1 和 d2。另外,如果您想让它尽可能快地运行,请注意简单的联接不能使用两个表上的索引,因此您可以节省创建其中一个索引的时间。在下面的代码中我们说明了这些要点。
值得注意的是,精确的计算可以对哪个包最快产生巨大的影响。例如,我们在下面进行合并和聚合。我们看到两者的结果几乎相反。在第一个示例中,从最快到最慢,我们得到:data.table、plyr、merge 和 sqldf,而在第二个示例中,sqldf、aggregate、data.table 和 plyr —— 几乎与第一个示例相反。在第一个示例中,sqldf 比 data.table 慢 3 倍,在第二个示例中,它比 plyr 快 200 倍,比 data.table 快 100 倍。下面我们展示了输入代码、合并的输出时序和聚合的输出时序。还值得注意的是,sqldf 基于数据库,因此可以处理大于 R 可以处理的对象(如果使用 sqldf 的 dbname 参数),而其他方法仅限于在主内存中处理。我们还用 sqlite 说明了 sqldf,但它也支持 H2 和 PostgreSQL 数据库。
library(plyr)
library(data.table)
library(sqldf)
set.seed(123)
N <- 1e5
d1 <- data.frame(x=sample(N,N), y1=rnorm(N))
d2 <- data.frame(x=sample(N,N), y2=rnorm(N))
g1 <- sample(1:1000, N, replace = TRUE)
g2<- sample(1:1000, N, replace = TRUE)
d <- data.frame(d1, g1, g2)
library(rbenchmark)
benchmark(replications = 1, order = "elapsed",
merge = merge(d1, d2),
plyr = join(d1, d2),
data.table = {
dt1 <- data.table(d1, key = "x")
dt2 <- data.table(d2, key = "x")
data.frame( dt1[dt2,list(x,y1,y2=dt2$y2)] )
},
sqldf = sqldf(c("create index ix1 on d1(x)",
"select * from main.d1 join d2 using(x)"))
)
set.seed(123)
N <- 1e5
g1 <- sample(1:1000, N, replace = TRUE)
g2<- sample(1:1000, N, replace = TRUE)
d <- data.frame(x=sample(N,N), y=rnorm(N), g1, g2)
benchmark(replications = 1, order = "elapsed",
aggregate = aggregate(d[c("x", "y")], d[c("g1", "g2")], mean),
data.table = {
dt <- data.table(d, key = "g1,g2")
dt[, colMeans(cbind(x, y)), by = "g1,g2"]
},
plyr = ddply(d, .(g1, g2), summarise, avx = mean(x), avy=mean(y)),
sqldf = sqldf(c("create index ix on d(g1, g2)",
"select g1, g2, avg(x), avg(y) from main.d group by g1, g2"))
)
比较合并计算的两个基准调用的输出为:
Joining by: x
test replications elapsed relative user.self sys.self user.child sys.child
3 data.table 1 0.34 1.000000 0.31 0.01 NA NA
2 plyr 1 0.44 1.294118 0.39 0.02 NA NA
1 merge 1 1.17 3.441176 1.10 0.04 NA NA
4 sqldf 1 3.34 9.823529 3.24 0.04 NA NA
比较聚合计算的基准调用的输出为:
test replications elapsed relative user.self sys.self user.child sys.child
4 sqldf 1 2.81 1.000000 2.73 0.02 NA NA
1 aggregate 1 14.89 5.298932 14.89 0.00 NA NA
2 data.table 1 132.46 47.138790 131.70 0.08 NA NA
3 plyr 1 212.69 75.690391 211.57 0.56 NA NA
关于performance - 在 R 中合并/连接 data.frames 的最快方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4322219/