Подтвердить что ты не робот

Самый быстрый широкоугольный поворот в 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, когда число "широких" полей (даты) является переменным и неизвестным заранее?

4b9b3361

Ответ 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