Ответ 1
Почему это так медленно? Небольшое исследование, в котором размещена публикация почтовой группы с августа 2011 года, где @hadley, автор пакета, указывает
Это недостаток того, как ddply всегда работает с данными кадры. Это будет немного быстрее, если вы используете обобщение вместо data.frame(потому что data.frame очень медленный), но я все еще думаю о том, как преодолеть это фундаментальное ограничение ddply Подход.
Что касается эффективного кода plyr, я тоже не знал. После того, как группа тестирования параметров и настольная маркировка выглядят так, мы можем сделать лучше.
summarize()
в вашей команде является просто вспомогательной функцией, чистой и простой. Мы можем заменить его своей собственной функцией суммы, поскольку она не помогает ни с чем, что еще не так просто, и аргументы .data
и .(price)
могут быть сделаны более явными. Результатом является
ddply( dd[, 2:3], ~price, function(x) sum( x$volume ) )
summarize
может показаться приятным, но он просто не быстрее простого вызова функции. Это имеет смысл; просто посмотрите на нашу небольшую функцию по сравнению с кодом для summarize
. Запуск ваших тестов с пересмотренной формулой дает заметный выигрыш. Не думайте, что это означает, что вы неправильно использовали plyr, вы этого не сделали, это просто неэффективно; вы ничего не можете с ним сделать, сделайте так же быстро, как и другие варианты.
По-моему, оптимизированная функция все еще воняет, поскольку она не ясна и должна быть мысленно проанализирована вместе с тем, что все еще смехотворно медленнее по сравнению с data.table(даже с коэффициентом усиления 60%).
В той же нитке, о которой говорилось выше, относительно медленности 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]
Пакет dataframe
был удален из CRAN, а затем из тестов вместе с версиями матричных функций.
Здесь результаты тестирования 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 здесь представлены микро-тесты времени агрегации данных_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
Кадр данных все еще остается в пыли. И не только это, но истекшее время system.time для заполнения структур данных тестовыми данными:
`d.df` (data.frame) 3.181 seconds.
`d.dt` (data.table) 0.418 seconds.
Как создание, так и агрегация файла data.frame медленнее, чем у data.table.
Работа с data.frame в R медленнее, чем некоторые альтернативы, но поскольку эталонные тесты показывают, что встроенные функции R выдувают воздух из воды. Даже управление data.frame как dplyr делает, что улучшает встроенные функции, не дает оптимальной скорости; где, поскольку data.table быстрее и в создании, и в агрегации, и в data.table делает то, что он делает, работая с /data.frames.
В конце концов...
Plyr медленный из-за того, как он работает и управляет манипуляцией 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