当键是字符时, *_join()
函数很慢。 你有什么计划来改善这个吗?
library("dplyr")
set.seed(71)
size1 <- 4*10^5
size2 <- size1 * 0.1
df1 <- data.frame(id=paste0("SERVICE_", 1:size1), value=rnorm(size1), stringsAsFactors=FALSE)
df2 <- data.frame(id=paste0("SERVICE_", sample(1:size1, size2)), value=rnorm(size2), stringsAsFactors=FALSE)
print(system.time(ljd <- dplyr::left_join(df1, df2, "id")))
#> user system elapsed
#> 15.50 0.07 15.56
我认为*_join()
在大多数情况下可以通过预先分解密钥来更快。 此外,我认为应该将键视为因素,因为没有人会尝试通过某些列连接,其中每一行都有不同的值。
print(system.time({
lvl <- unique(c(df1$id, df2$id))
ljd <- dplyr::left_join(mutate(df1, id=factor(id, levels = lvl)),
mutate(df2, id=factor(id, levels = lvl)),
"id")
})
)
#> user system elapsed
#> 0.33 0.10 0.42
dplyr 应该利用 R 的全局字符串缓存在使用内存对象时进行字符串匹配。 您只需要检查相关的字符指针是否相同。
见https://github.com/wch/r-source/blob/4a2026e8e/src/main/relop.c#L564 -L569, https : //github.com/wch/r-source/blob/9d4e23e/src /main/memory.c#L3878 -L3894 用于 C 实现。
这比实际上要复杂一些。 有时两个不同的指针是相同的字符串但具有不同的编码,我们希望join
将它们视为相等。
但是你的观点很好,我现在正在研究它。 我们基于某种排序(尊重编码等)对字符串进行散列,但实际上我们只需要能够区分它们,而不必对它们进行排名。
待定
现在得到:
set.seed(71)
size1 <- 4*10^5
size2 <- size1 * 0.1
df1 <- data.frame(id=paste0("SERVICE_", 1:size1), value=rnorm(size1), stringsAsFactors=FALSE)
df2 <- data.frame(id=paste0("SERVICE_", sample(1:size1, size2)), value=rnorm(size2), stringsAsFactors=FALSE)
print(system.time(ljd <- dplyr::left_join(df1, df2, "id")))
#> user system elapsed
#> 0.333 0.013 0.346
print(system.time({
lvl <- unique(c(df1$id, df2$id))
ljd <- dplyr::left_join(mutate(df1, id=factor(id, levels = lvl)),
mutate(df2, id=factor(id, levels = lvl)),
"id") %>% mutate( id = as.character(id) )
})
)
#> user system elapsed
#> 0.255 0.007 0.262
这比我们以前的要好得多。 仍然高于使用factor
的建议实现。 我可能会继续使用它。
哇,好快!!! 非常感谢:+1:
@romainfrancois这是临时更新吗? 我是用最新版本的dplyr运行这个测试的,版本是0.4.3,但是速度慢。
最有用的评论
现在得到:
这比我们以前的要好得多。 仍然高于使用
factor
的建议实现。 我可能会继续使用它。