为什么plyr这么慢?

2024-01-19

我认为我错误地使用了 plyr。有人可以告诉我这是否是“高效”的 plyr 代码吗?

require(plyr)
plyr <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume)) 

一些背景信息:我有一些大的聚合问题,我注意到它们每个都需要一些时间。在尝试解决这些问题的过程中,我对 R 中各种聚合过程的性能产生了兴趣。

我测试了一些聚合方法 - 结果发现自己整天都在等待。

当我最终得到结果时,我发现 plyr 方法和其他方法之间存在巨大差距 - 这让我觉得我做错了什么。

我运行了以下代码(我想我应该在使用时检查新的数据帧包):

require(plyr)
require(data.table)
require(dataframe)
require(rbenchmark)
require(xts)

plyr <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume)) 
t.apply <- function(dd) unlist(tapply(dd$volume, dd$price, sum))
t.apply.x <- function(dd) unlist(tapply(dd[,2], dd[,1], sum))
l.apply <- function(dd) unlist(lapply(split(dd$volume, dd$price), sum))
l.apply.x <- function(dd) unlist(lapply(split(dd[,2], dd[,1]), sum))
b.y <- function(dd) unlist(by(dd$volume, dd$price, sum))
b.y.x <- function(dd) unlist(by(dd[,2], dd[,1], sum))
agg <- function(dd) aggregate(dd$volume, list(dd$price), sum)
agg.x <- function(dd) aggregate(dd[,2], list(dd[,1]), sum)
dtd <- function(dd) dd[, sum(volume), by=(price)]

obs <- c(5e1, 5e2, 5e3, 5e4, 5e5, 5e6, 5e6, 5e7, 5e8)
timS <- timeBasedSeq('20110101 083000/20120101 083000')

bmkRL <- list(NULL)

for (i in 1:5){
  tt <- timS[1:obs[i]]

  for (j in 1:8){
    pxl <- seq(0.9, 1.1, by= (1.1 - 0.9)/floor(obs[i]/(11-j)))
    px <- sample(pxl, length(tt), replace=TRUE)
    vol <- rnorm(length(tt), 1000, 100)

    d.df <- base::data.frame(time=tt, price=px, volume=vol)
    d.dfp <- dataframe::data.frame(time=tt, price=px, volume=vol)
    d.matrix <- as.matrix(d.df[,-1])
    d.dt <- data.table(d.df)

    listLabel <- paste('i=',i, 'j=',j)

    bmkRL[[listLabel]] <- benchmark(plyr(d.df), plyr(d.dfp), t.apply(d.df),     
                         t.apply(d.dfp), t.apply.x(d.matrix), 
                         l.apply(d.df), l.apply(d.dfp), l.apply.x(d.matrix),
                         b.y(d.df), b.y(d.dfp), b.y.x(d.matrix), agg(d.df),
                         agg(d.dfp), agg.x(d.matrix), dtd(d.dt),
          columns =c('test', 'elapsed', 'relative'),
          replications = 10,
          order = 'elapsed')
  }
}

该测试本来应该检查 5e8,但花了太长时间 - 主要是由于 plyr。 5e5最终表说明了问题:

$`i= 5 j= 8`
                  test  elapsed    relative
15           dtd(d.dt)    4.156    1.000000
6        l.apply(d.df)   15.687    3.774543
7       l.apply(d.dfp)   16.066    3.865736
8  l.apply.x(d.matrix)   16.659    4.008422
4       t.apply(d.dfp)   21.387    5.146054
3        t.apply(d.df)   21.488    5.170356
5  t.apply.x(d.matrix)   22.014    5.296920
13          agg(d.dfp)   32.254    7.760828
14     agg.x(d.matrix)   32.435    7.804379
12           agg(d.df)   32.593    7.842397
10          b.y(d.dfp)   98.006   23.581809
11     b.y.x(d.matrix)   98.134   23.612608
9            b.y(d.df)   98.337   23.661453
1           plyr(d.df) 9384.135 2257.972810
2          plyr(d.dfp) 9384.448 2258.048123

这是正确的吗?为什么 plyr 2250x 比data.table?为什么使用新的数据框架包没有产生影响?

会话信息是:

> sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] xts_0.8-6        zoo_1.7-7        rbenchmark_0.3   dataframe_2.5    data.table_1.8.1     plyr_1.7.1      

loaded via a namespace (and not attached):
[1] grid_2.15.1    lattice_0.20-6 tools_2.15.1 

Why这么慢吗?一项小研究发现了 2011 年 8 月的一个邮件组帖子,其中软件包作者 @hadley,states https://groups.google.com/forum/?fromgroups#!msg/manipulatr/Xo3-2FBI35k/9pClNUuxoPIJ%5B1-25%5D

这是 ddply 始终处理数据的方式的一个缺点 帧。如果你用summary代替的话会快一点 data.frame(因为data.frame非常慢),但我还在想 关于如何克服 ddply 的这一基本限制 方法。


至于是高效的plyr 代码我也不知道。经过一系列参数测试和基准测试后,看起来我们可以做得更好。

The summarize()在你的命令中只是一个辅助函数,纯粹而简单。我们可以用我们自己的 sum 函数替换它,因为它对任何不简单的事情没有帮助,并且.data and .(price)可以使论点更加明确。结果是

ddply( dd[, 2:3], ~price, function(x) sum( x$volume ) )

The summarize看起来不错,但它并不比简单的函数调用更快。这说得通;看看我们的小函数与code https://github.com/hadley/plyr/blob/master/R/helper-summarise.r for summarize。使用修改后的公式运行基准测试会产生显着的增益。不要认为这意味着你错误地使用了 plyr,你没有,它只是效率低下;无论你对它做什么,它都不会像其他选项一样快。

在我看来,优化后的函数仍然很糟糕,因为它不清楚,必须在心里解析,而且与 data.table 相比仍然慢得离谱(即使有 60% 的增益)。


在相同的thread https://groups.google.com/forum/?fromgroups#!msg/manipulatr/Xo3-2FBI35k/9pClNUuxoPIJ%5B1-25%5D上面提到,关于plyr的缓慢,提到了一个plyr2项目。自 plyr 作者发布原始答案以来dplyr作为plyr的继承者。虽然 plyr 和 dplyr 都被宣传为数据操作工具,并且您的主要兴趣是聚合,但您可能仍然对新软件包的基准测试结果感兴趣以进行比较,因为它具有经过重新设计的后端以提高性能。

plyr_Original   <- function(dd) ddply( dd, .(price), summarise, ss=sum(volume))
plyr_Optimized  <- function(dd) ddply( dd[, 2:3], ~price, function(x) sum( x$volume ) )

dplyr <- function(dd) dd %.% group_by(price) %.% summarize( sum(volume) )    

data_table <- function(dd) dd[, sum(volume), keyby=price]

The dataframe package has been removed from CRAN and subsequently from the tests, along with the matrix function versions.

这是i=5, j=8基准测试结果:

$`obs= 500,000 unique prices= 158,286 reps= 5`
                  test elapsed relative
9     data_table(d.dt)   0.074    1.000
4          dplyr(d.dt)   0.133    1.797
3          dplyr(d.df)   1.832   24.757
6        l.apply(d.df)   5.049   68.230
5        t.apply(d.df)   8.078  109.162
8            agg(d.df)  11.822  159.757
7            b.y(d.df)  48.569  656.338
2 plyr_Optimized(d.df) 148.030 2000.405
1  plyr_Original(d.df) 401.890 5430.946

毫无疑问,优化有一点帮助。看看d.df功能;他们就是无法竞争。

为了稍微了解一下 data.frame 结构的缓慢程度,这里是使用更大的测试数据集的 data_table 和 dplyr 聚合时间的微基准(i=8,j=8).

$`obs= 50,000,000 unique prices= 15,836,476 reps= 5`
Unit: seconds
             expr    min     lq median     uq    max neval
 data_table(d.dt)  1.190  1.193  1.198  1.460  1.574    10
      dplyr(d.dt)  2.346  2.434  2.542  2.942  9.856    10
      dplyr(d.df) 66.238 66.688 67.436 69.226 86.641    10

数据框是still留在尘埃里。不仅如此,这里还有用测试数据填充数据结构所用的 system.time:

`d.df` (data.frame)  3.181 seconds.
`d.dt` (data.table)  0.418 seconds.

data.frame 的创建和聚合都比 data.table 慢。

使用 data.framein R is比某些替代方案慢,但正如基准测试所示,内置的 R 函数将 plyr 打得落花流水。即使像 dplyr 那样管理 data.frame(它改进了内置功能),也无法提供最佳速度;其中 data.table是比较快的无论是创作还是聚合anddata.table 执行与 data.frames 一起工作时的操作。

到底...

由于方式原因,Plyr 速度很慢it使用并管理 data.frame 操作.

[punt:: 请参阅对原始问题的评论]。


## R version 3.0.2 (2013-09-25)
## Platform: x86_64-pc-linux-gnu (64-bit)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] microbenchmark_1.3-0 rbenchmark_1.0.0     xts_0.9-7           
## [4] zoo_1.7-11           data.table_1.9.2     dplyr_0.1.2         
## [7] plyr_1.8.1           knitr_1.5.22        
## 
## loaded via a namespace (and not attached):
## [1] assertthat_0.1  evaluate_0.5.2  formatR_0.10.4  grid_3.0.2     
## [5] lattice_0.20-27 Rcpp_0.11.0     reshape2_1.2.2  stringr_0.6.2  
## [9] tools_3.0.2

Data-Generating gist .rmd https://gist.github.com/Thell/9265593

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么plyr这么慢? 的相关文章

  • glmnet R 包中的 cv.glmnet 出现“drop(y %*% rep(1, nc)) 错误”错误

    我有一个返回 cv glmnet 模型的 auc 值的函数 尽管不是大多数时间 但在执行 cv glmnet 函数时 它经常返回以下错误 下降误差 y 代表 1 NC 在为函数 drop 选择方法时评估参数 x 时出错 y 中的错误 rep
  • Pandas DataFrame - 列 whos dtype=='category' 上的聚合导致性能下降

    我使用内存使用量较高的大数据帧 并且我读到 如果更改重复值列上的数据类型 我可以节省大量内存 我尝试了一下 确实内存使用量下降了 25 但随后我遇到了我无法理解的性能缓慢问题 我对 dtype 类别 列进行分组聚合 在更改 dtype 之前
  • 数据集子集的回归

    我想做以下事情并需要一些帮助 分别计算 身高 与 年龄 的斜率和截距 lm Height Age 一 每个人 二 性别 并创建一个包含结果 斜率和截距 的表 我可以使用 申请 吗 在下一步中 我想做一个统计测试 以确定性别之间的斜率和截距是
  • 在 R 中将本地日期时间转换为 UTC

    如何将本地日期时间转换为以下格式 12 31 2014 6 42 52 PM R 中的 UTC 我试过这个 as POSIXct as Date 12 31 2014 6 42 52 PM format m d Y H M S tz UTC
  • 是否可以使用像“tz=NULL”这样的东西?...“as.POSIXct”默认为依赖于语言环境的时区(与“as.Date”不同),这会导致问题

    我知道这是一个长期存在 根深蒂固的问题 但这是我经常遇到的问题 而且我看到初学者R经常与此斗争 我希望有一个令人满意的解决方案 到目前为止 我的谷歌和 SO 搜索都是空的 但如果在其他地方重复 请指出正确的方向 TL DR 有没有办法使用类
  • 不同的分位数:箱线图与小提琴图

    require ggplot2 require cowplot d iris ggplot2 ggplot d aes factor 0 Sepal Length geom violin fill black alpha 0 2 draw
  • R 在 Ubuntu 中通过代理连接

    我在 Ubuntu 12 04 上安装了 RStudio 0 97 168 当我尝试安装 gstat 库时出现以下错误 install packages gstat dependencies TRUE Warning in install
  • Spark中DataFrame、Dataset、RDD的区别

    我只是想知道有什么区别RDD and DataFrame Spark 2 0 0 DataFrame 只是一个类型别名Dataset Row 在阿帕奇火花 你能将其中一种转换为另一种吗 首先是DataFrame是从SchemaRDD 是的
  • corr.test 与 cor.test p 值

    我正在尝试使用 psych 包 psych 1 6 9 中的 corr test 但在使用 method spearman 时 它似乎给出了与 cor test 不同的 p 值 相关系数相同 但 p 值不同 我整理了一些示例代码和输出 如下
  • R:使用 as.formula 修复模型中的模型调用

    我有一个gls模型 其中我将公式 来自另一个对象 分配给模型 equation lt as formula aic obj row model gt equation temp avg I year 1950 mod1 lt gls equ
  • 对 R/Sweave 进行编程以获得正确的 \Sexpr 输出

    我在为 Sweave 进行 R 编程时遇到了一些问题 rstats twitter 小组经常指出这里 所以我想我应该把这个问题向大家提出 我是一名分析师 而不是程序员 所以在我的第一篇文章中请放轻松 问题是 我正在使用 R 在 Sweave
  • 如何在 R 中使用 msgbox [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何在中显示消息框R 我正在寻找类似的东西msgbox在 VBA 中 因此我可以向用户发出有关问题的警报 此外 我想允许一些用户交互 例如
  • 将英寸高度的字符向量转换为厘米?

    我得到一个字符向量 tibble H c 6 2 5 10 5 5 5 1 5 5 5 4 我想将其转换为厘米 请告知我该怎么做 有几种方法可以使用 1 阅读与fread粘贴到单个字符串后 library data table fread
  • 整理包中的字段说明

    我很抱歉 因为我知道这个答案可能出现在编写 R 包的手册中 但在我阅读和查看其他包的整理字段时 我无法 100 弄清楚该字段的用途 用简单的语言 我的是英语 来看 包的描述文件中的整理字段有什么作用 人们想在那里放什么 我认为这来自于某个时
  • 如何将变量传递给 ddply 中的自定义函数?

    考虑以下数据 d data frame experiment as factor c foo foo foo bar bar si runif 5 ti runif 5 我想进行相关性测试si and ti 对于每个experiment因素
  • 如何对plot_ly()图表进行分面?

    Using ggplot2 and plotly制作交互式散点图facet wrap library ggplot2 library plotly g lt iris gt ggplot aes x Sepal Length y Sepal
  • 通过排列进行多组测试

    我有一个 df 其中包含与两个实验相关的两组值 value 1 和 value 2 一个实验包含两组 0 和 1 另一个实验包含三组 0 1 2 test group Value 1 Value 2 AA 0 15 1 11 2 AA 0
  • 如何将带有几行代码的字符数组转换为 data.frame?

    我有以下数组 my list lt c Jan 01 Dec 31 00 00 24 00 Jan 01 Jun 30 12 00 18 00 Jul 06 Dec 31 09 00 19 00 导致以下结果的最短代码是什么 x1 x2 x
  • 动态显示仪表板页面

    我有一个实用的闪亮应用程序 它使用shinydashboard包裹 新功能需要特定于用户的行为 例如 针对不同的用户名使用不同的数据集 因此我打算 显示登录表单 验证凭据并设置反应值LoggedIn to true如果成功的话 显示实际情况
  • 修改x轴刻度标签

    我正在尝试更改由生成的箱线图的 x 轴刻度标签ggplot2 x 轴是一个分类变量 HabFac 我想要的是将其刻度更改为 6 个化学品 A E 下面是我的代码 raw data read table Read data p TT ggpl

随机推荐