Самый быстрый широкоугольный поворот в R
Я имею дело с простой таблицей формы
date variable value
1970-01-01 V1 0.434
1970-01-01 V2 12.12
1970-01-01 V3 921.1
1970-01-02 V1 -1.10
1970-01-03 V3 0.000
1970-01-03 V5 312e6
... ... ...
Пара (дата, переменная) уникальна. Я хотел бы преобразовать эту таблицу в широкоформатную.
date V1 V2 V3 V4 V5
1970-01-01 0.434 12.12 921.1 NA NA
1970-01-02 -1.10 NA NA NA NA
1970-01-03 0.000 NA NA NA 312e6
И я хотел бы сделать это самым быстрым способом, так как я должен повторять операцию повторно над таблицами с записями 1e6. В собственном режиме R я считаю, что как tapply()
, reshape()
, так и d*ply()
доминируют по скорости на data.table
. Я бы хотел проверить производительность последнего на основе решения на базе sqlite (или другого БД). Это было сделано раньше? Есть ли выигрыш в производительности? И как преобразовать высоту в ширину в sqlite, когда число "широких" полей (даты) является переменным и неизвестным заранее?
Ответы
Ответ 1
Я использую подход, основанный на том, что делает tapply
, но примерно на порядок быстрее (прежде всего, поскольку вызов функции для каждой ячейки не существует).
Сроки использования tall
из сообщения Прасада:
pivot = function(col, row, value) {
col = as.factor(col)
row = as.factor(row)
mat = array(dim = c(nlevels(row), nlevels(col)), dimnames = list(levels(row), levels(col)))
mat[(as.integer(col) - 1L) * nlevels(row) + as.integer(row)] = value
mat
}
> system.time( replicate(100, wide <- with(tall, tapply( value, list(dt,tkr), identity))))
user system elapsed
11.31 0.03 11.36
> system.time( replicate(100, wide <- with(tall, pivot(tkr, dt, value))))
user system elapsed
0.9 0.0 0.9
Что касается возможных проблем с заказом, не должно быть никаких проблем:
> a <- with(tall, pivot(tkr, dt, value))
> b <- with(tall[sample(nrow(tall)), ], pivot(tkr, dt, value))
> all.equal(a, b)
[1] TRUE
Ответ 2
Несколько замечаний. Несколько вопросов SO касаются того, как сделать высокий по ширине поворот в Sql (ite): здесь и здесь. Я не слишком сильно смотрел на них, но у меня сложилось впечатление, что делать это в SQL уродливо, так как в вашем запросе sql необходимо явно указать все возможные ключи в запросе! (кто-то, пожалуйста, поправьте меня, если я ошибаюсь). Что касается data.table
, вы можете выполнить групповые операции очень быстро, но я не вижу, как вы можете фактически привести результат в широкий формат.
Если вы хотите сделать это исключительно в R, я думаю, что tapply
- чемпион скорости здесь, намного быстрее, чем acast
из reshape2
:
Создайте несколько высоких данных с некоторыми отверстиями в нем, чтобы убедиться, что код работает правильно:
tall <- data.frame( dt = rep(1:100, 100),
tkr = rep( paste('v',1:100,sep=''), each = 100),
value = rnorm(1e4)) [-(1:5), ]
> system.time( replicate(100, wide <- with(tall, tapply( value, list(dt,tkr), identity))))
user system elapsed
4.73 0.00 4.73
> system.time( replicate(100, wide <- acast( tall, tkr ~ dt)))
user system elapsed
7.93 0.03 7.98