Когда из-за очень больших данных расчеты занимают много времени и, следовательно, мы не хотим, чтобы они зависали, было бы полезно заранее узнать, какой метод изменения формы использовать.
В последнее время методыдля преобразования данных были дополнительно разработаны данные о производительности, например, data.table::dcast
и tidyr::spread
.Особенно dcast.data.table
, кажется, устанавливает тон [1] , [2] , [3] , [4] .Это делает другие методы, поскольку базовые R reshape
в тестах кажутся устаревшими и почти бесполезными [5] .
Теория
Однако , я слышал, что reshape
по-прежнему непобедим, когда дело доходит до очень больших наборов данных (вероятно, превышающих объем ОЗУ), потому что это единственный метод, который может обрабатывать их, и, следовательно, он по-прежнему имеет правосуществовать.Соответствующий отчет о сбое с использованием reshape2::dcast
поддерживает эту точку [6] .По крайней мере, одна ссылка дает подсказку, что reshape()
действительно может иметь преимущества перед reshape2::dcast
для действительно "больших вещей" [7] .
Метод
В поисках доказательств этого я подумал, что стоит потратить время на некоторые исследования.Поэтому я провел тест с имитированными данными разного размера, которые все больше расходуют ОЗУ для сравнения reshape
, dcast
, dcast.data.table
и spread
.Я посмотрел на простые наборы данных с тремя столбцами, с различным количеством строк, чтобы получить разные размеры (см. Код в самом низу).
> head(df1, 3)
id tms y
1 1 1970-01-01 01:00:01 0.7463622
2 2 1970-01-01 01:00:01 0.1417795
3 3 1970-01-01 01:00:01 0.6993089
Размер оперативной памяти составлял всего 8 ГБ, что было моим порогоммоделировать "очень большие" наборы данных.Чтобы сохранить разумное время для расчетов, я сделал только 3 измерения для каждого метода и сосредоточился на изменении формы с длинного на широкий.
Результаты
unit: seconds
expr min lq mean median uq max neval size.gb size.ram
1 dcast.DT NA NA NA NA NA NA 3 8.00 1.000
2 dcast NA NA NA NA NA NA 3 8.00 1.000
3 tidyr NA NA NA NA NA NA 3 8.00 1.000
4 reshape 490988.37 492843.94 494699.51 495153.48 497236.03 499772.56 3 8.00 1.000
5 dcast.DT 3288.04 4445.77 5279.91 5466.31 6375.63 10485.21 3 4.00 0.500
6 dcast 5151.06 5888.20 6625.35 6237.78 6781.14 6936.93 3 4.00 0.500
7 tidyr 5757.26 6398.54 7039.83 6653.28 7101.28 7162.74 3 4.00 0.500
8 reshape 85982.58 87583.60 89184.62 88817.98 90235.68 91286.74 3 4.00 0.500
9 dcast.DT 2.18 2.18 2.18 2.18 2.18 2.18 3 0.20 0.025
10 tidyr 3.19 3.24 3.37 3.29 3.46 3.63 3 0.20 0.025
11 dcast 3.46 3.49 3.57 3.52 3.63 3.74 3 0.20 0.025
12 reshape 277.01 277.53 277.83 278.05 278.24 278.42 3 0.20 0.025
13 dcast.DT 0.18 0.18 0.18 0.18 0.18 0.18 3 0.02 0.002
14 dcast 0.34 0.34 0.35 0.34 0.36 0.37 3 0.02 0.002
15 tidyr 0.37 0.39 0.42 0.41 0.44 0.48 3 0.02 0.002
16 reshape 29.22 29.37 29.49 29.53 29.63 29.74 3 0.02 0.002
( Примечание: Тесты проводились на вторичном MacBook Pro с Intel Core i5 2,5 ГГц, 8 ГБ оперативной памяти DDR3 1600 МГц.)
Очевидно, dcast.data.table
кажется всегда самым быстрым.Как и ожидалось, все упакованные подходы потерпели неудачу с очень большими наборами данных, возможно, потому что вычисления тогда превысили объем оперативной памяти:
Error: vector memory exhausted (limit reached?)
Timing stopped at: 1.597e+04 1.864e+04 5.254e+04
Только reshape
обрабатывал все размеры данных, хотя и очень медленно.
Заключение
Методы пакета, такие как dcast
и spread
, неоценимы для наборов данных, которые меньше ОЗУ или чьи вычисления не исчерпывают ОЗУ.Если набор данных больше, чем объем оперативной памяти, методы пакета не будут выполнены, и мы должны использовать reshape
.
Вопрос
Можно ли сделать такой вывод?Может ли кто-нибудь немного разъяснить, почему методы data.table/reshape
и tidyr
терпят неудачу и каковы их методологические отличия от reshape
?Является ли единственная альтернатива для больших данных надежной, но медленной лошадью reshape
?Что мы можем ожидать от методов, которые здесь не тестировались как tapply
, unstack
и xtabs
подходы [8] , [9] ?
Или, короче говоря: Какая более быстрая альтернатива, если что-либо, кроме reshape
, выходит из строя?
Данные / Код
# 8GB version
n <- 1e3
t1 <- 2.15e5 # approx. 8GB, vary to increasingly exceed RAM
df1 <- expand.grid(id=1:n, tms=as.POSIXct(1:t1, origin="1970-01-01"))
df1$y <- rnorm(nrow(df1))
dim(df1)
# [1] 450000000 3
> head(df1, 3)
id tms y
1 1 1970-01-01 01:00:01 0.7463622
2 2 1970-01-01 01:00:01 0.1417795
3 3 1970-01-01 01:00:01 0.6993089
object.size(df1)
# 9039666760 bytes
library(data.table)
DT1 <- as.data.table(df1)
library(microbenchmark)
library(tidyr)
# NOTE: this runs for quite a while!
mbk <- microbenchmark(reshape=reshape(df1, idvar="tms", timevar="id", direction="wide"),
dcast=dcast(df1, tms ~ id, value.var="y"),
dcast.dt=dcast(DT1, tms ~ id, value.var="y"),
tidyr=spread(df1, id, y),
times=3L)