Ответ 1
Этот старый вопрос часто используется как цель обмана (помечен r-faq
). На сегодняшний день было три ответа, предлагая 6 разных подходов, но не имеет контрольного показателя, поскольку руководство, которое из подходов является самым быстрым 1.
Референсные решения включают
- подход Мэтью Лундберга к базе R, но изменен в соответствии с комментарием Rich Scriven,
- Jaap два метода
data.table
и два подходаdplyr
/tidyr
, - Ананда
splitstackshape
решение, - и два дополнительных варианта методов Jaap
data.table
.
В целом 8 различных методов были сопоставлены с 6 различными размерами кадров данных с использованием пакета microbenchmark
(см. код ниже).
Данные выборок, предоставленные OP, состоят только из 20 строк. Для создания больших кадров данных эти 20 строк просто повторяются 1, 10, 100, 1000, 10000 и 100000 раз, что дает размер проблем до 2 миллионов строк.
Результаты тестов
Результаты тестов показывают, что для достаточно больших кадров данных все методы data.table
работают быстрее, чем любой другой метод. Для фреймов данных, содержащих более 5000 строк, метод Jaap data.table
2 и вариант DT3
являются самыми быстрыми, значениями быстрее, чем самые медленные методы.
Замечательно, что тайминги двух методов tidyverse
и решения splistackshape
настолько схожи, что трудно отличить кривые на диаграмме. Они являются самыми медленными из сравниваемых методов во всех размерах фреймов данных.
Для меньших кадров данных решение Matt base R и метод data.table
4, как представляется, имеют меньшие накладные расходы, чем другие методы.
Код
director <-
c("Aaron Blaise,Bob Walker", "Akira Kurosawa", "Alan J. Pakula",
"Alan Parker", "Alejandro Amenabar", "Alejandro Gonzalez Inarritu",
"Alejandro Gonzalez Inarritu,Benicio Del Toro", "Alejandro González Iñárritu",
"Alex Proyas", "Alexander Hall", "Alfonso Cuaron", "Alfred Hitchcock",
"Anatole Litvak", "Andrew Adamson,Marilyn Fox", "Andrew Dominik",
"Andrew Stanton", "Andrew Stanton,Lee Unkrich", "Angelina Jolie,John Stevenson",
"Anne Fontaine", "Anthony Harvey")
AB <- c("A", "B", "A", "A", "B", "B", "B", "A", "B", "A", "B", "A",
"A", "B", "B", "B", "B", "B", "B", "A")
library(data.table)
library(magrittr)
Определить функцию для тестовых прогонов размера проблемы n
run_mb <- function(n) {
# compute number of benchmark runs depending on problem size `n`
mb_times <- scales::squish(10000L / n , c(3L, 100L))
cat(n, " ", mb_times, "\n")
# create data
DF <- data.frame(director = rep(director, n), AB = rep(AB, n))
DT <- as.data.table(DF)
# start benchmarks
microbenchmark::microbenchmark(
matt_mod = {
s <- strsplit(as.character(DF$director), ',')
data.frame(director=unlist(s), AB=rep(DF$AB, lengths(s)))},
jaap_DT1 = {
DT[, lapply(.SD, function(x) unlist(tstrsplit(x, ",", fixed=TRUE))), by = AB
][!is.na(director)]},
jaap_DT2 = {
DT[, strsplit(as.character(director), ",", fixed=TRUE),
by = .(AB, director)][,.(director = V1, AB)]},
jaap_dplyr = {
DF %>%
dplyr::mutate(director = strsplit(as.character(director), ",")) %>%
tidyr::unnest(director)},
jaap_tidyr = {
tidyr::separate_rows(DF, director, sep = ",")},
cSplit = {
splitstackshape::cSplit(DF, "director", ",", direction = "long")},
DT3 = {
DT[, strsplit(as.character(director), ",", fixed=TRUE),
by = .(AB, director)][, director := NULL][
, setnames(.SD, "V1", "director")]},
DT4 = {
DT[, .(director = unlist(strsplit(as.character(director), ",", fixed = TRUE))),
by = .(AB)]},
times = mb_times
)
}
Запустить тест производительности для разных размеров проблем
# define vector of problem sizes
n_rep <- 10L^(0:5)
# run benchmark for different problem sizes
mb <- lapply(n_rep, run_mb)
Подготовить данные для печати
mbl <- rbindlist(mb, idcol = "N")
mbl[, n_row := NROW(director) * n_rep[N]]
mba <- mbl[, .(median_time = median(time), N = .N), by = .(n_row, expr)]
mba[, expr := forcats::fct_reorder(expr, -median_time)]
Создать диаграмму
library(ggplot2)
ggplot(mba, aes(n_row, median_time*1e-6, group = expr, colour = expr)) +
geom_point() + geom_smooth(se = FALSE) +
scale_x_log10(breaks = NROW(director) * n_rep) + scale_y_log10() +
xlab("number of rows") + ylab("median of execution time [ms]") +
ggtitle("microbenchmark results") + theme_bw()
Информация о сеансе и версии пакета (выдержка)
devtools::session_info()
#Session info
# version R version 3.3.2 (2016-10-31)
# system x86_64, mingw32
#Packages
# data.table * 1.10.4 2017-02-01 CRAN (R 3.3.2)
# dplyr 0.5.0 2016-06-24 CRAN (R 3.3.1)
# forcats 0.2.0 2017-01-23 CRAN (R 3.3.2)
# ggplot2 * 2.2.1 2016-12-30 CRAN (R 3.3.2)
# magrittr * 1.5 2014-11-22 CRAN (R 3.3.0)
# microbenchmark 1.4-2.1 2015-11-25 CRAN (R 3.3.3)
# scales 0.4.1 2016-11-09 CRAN (R 3.3.2)
# splitstackshape 1.4.2 2014-10-23 CRAN (R 3.3.3)
# tidyr 0.6.1 2017-01-10 CRAN (R 3.3.2)
1 Мое любопытство было вызвано этим буйным комментарием Великолепно! Заказы на величину быстрее! на tidyverse
ответ вопроса, который был закрыт как дубликат этого вопроса.