log*_*thy 16 performance r cardinality dplyr magrittr
我认为一般来说使用%>%
不会对速度产生明显影响.但在这种情况下,它运行速度慢了4倍.
library(dplyr)
library(microbenchmark)
set.seed(0)
dummy_data <- dplyr::data_frame(
id=floor(runif(10000, 1, 10000))
, label=floor(runif(10000, 1, 4))
)
microbenchmark(dummy_data %>% group_by(id) %>% summarise(list(unique(label))))
microbenchmark(dummy_data %>% group_by(id) %>% summarise(label %>% unique %>% list))
Run Code Online (Sandbox Code Playgroud)
没有管道:
min lq mean median uq max neval
1.691441 1.739436 1.841157 1.812778 1.880713 2.495853 100
Run Code Online (Sandbox Code Playgroud)
带管:
min lq mean median uq max neval
6.753999 6.969573 7.167802 7.052744 7.195204 8.833322 100
Run Code Online (Sandbox Code Playgroud)
为什么%>%
在这种情况下会这么慢?有没有更好的方法来写这个?
Spa*_*man 32
在编写与以前"可忽略的"时间相关的单线时,在现实世界的完整应用中可能产生的微不足道的影响变得不可忽视.我怀疑如果你对你的测试进行了剖析,那么大部分时间都在这个summarize
子句中,所以让microbenchmark类似于那样:
> set.seed(99);z=sample(10000,4,TRUE)
> microbenchmark(z %>% unique %>% list, list(unique(z)))
Unit: microseconds
expr min lq mean median uq max neval
z %>% unique %>% list 142.617 144.433 148.06515 145.0265 145.969 297.735 100
list(unique(z)) 9.289 9.988 10.85705 10.5820 11.804 12.642 100
Run Code Online (Sandbox Code Playgroud)
这与您的代码有所不同,但说明了重点.管道比较慢.
因为管道需要将R的调用重组为功能评估正在使用的相同的调用,然后对它们进行评估.因此,有要慢一些.多少取决于功能的快速程度.在R中调用unique
并且list
相当快,所以这里的全部差异是管道开销.
像这样的分析表达式表明我大部分时间花在管道函数上:
total.time total.pct self.time self.pct
"microbenchmark" 16.84 98.71 1.22 7.15
"%>%" 15.50 90.86 1.22 7.15
"eval" 5.72 33.53 1.18 6.92
"split_chain" 5.60 32.83 1.92 11.25
"lapply" 5.00 29.31 0.62 3.63
"FUN" 4.30 25.21 0.24 1.41
..... stuff .....
Run Code Online (Sandbox Code Playgroud)
然后在大约第15位的某处,真正的工作完成:
"as.list" 1.40 8.13 0.66 3.83
"unique" 1.38 8.01 0.88 5.11
"rev" 1.26 7.32 0.90 5.23
Run Code Online (Sandbox Code Playgroud)
然而,如果你只是将这些函数称为钱伯斯的意图,那么R直接归结为它:
total.time total.pct self.time self.pct
"microbenchmark" 2.30 96.64 1.04 43.70
"unique" 1.12 47.06 0.38 15.97
"unique.default" 0.74 31.09 0.64 26.89
"is.factor" 0.10 4.20 0.10 4.20
Run Code Online (Sandbox Code Playgroud)
因此经常引用的建议是,管道在你的大脑认为是连锁的命令行上是可以的,但不是在可能是时间关键的功能中.在实践中,这个开销可能会在一次调用glm
几百个数据点时被消除,但这是另一个故事....