преобразование времени начала и окончания активности в бинарные данные для нескольких групп в R dplyr/tidyr

У меня есть данные, которые выглядят примерно так:

foo <- data.frame(userid = c("a","a","b","b","b"),
                  activity = factor(c("x","y","z","z","x")),
                  st=c(0, 20,   0, 10, 25), # start time
                  et=c(20, 30, 10, 25, 30)) # end time

и я хочу для каждого идентификатора пользователя преобразовывать данные об активности в пятиминутные интервалы времени. Результат будет выглядеть примерно так:

result <- data.frame(userid = c("a", "b"),
                         x1 = c("x", "z"),
                         x2 = c("x", "z"),
                         x3 = c("x", "z"),
                         x4 = c("x", "z"),
                         x5 = c("y", "z"),
                         x6 = c("y", "x"))

Следующий подход работает, но он довольно громоздкий и очень медленный. Это занимает около 15 минут на моем наборе данных скромного размера.

library(dplyr)
library(tidyr)

lvls <- levels(foo$activity)

time_bin <- function(st, et, act) {
  bins <- seq(0, 30, by=5)
  tb <- as.integer(bins>=st & bins<et)*as.integer(act)
  tb[tb>0] <- lvls[tb]
  data.frame(tb=tb, bins=bins)
}

new_foo <- 
  foo %>% 
  rowwise() %>%
  do(data.frame(., time_bin(.$st, .$et, .$activity))) %>%
  select(-(activity:et)) %>%
  group_by(userid) %>%
  subset(tb>0) %>%
  spread(bins, tb)

Есть ли более быстрый или удобный способ сделать это?


person Bryan    schedule 10.04.2015    source источник
comment
Можем ли мы предположить во входных данных, что действия для каждого пользователя а) не перекрываются, б) между ними нет промежутков и в) отсортированы по возрастанию времени? Возможно, вы могли бы дать более длинный ввод (генерируемый случайным образом), который проверяет производительность? Вы имели в виду, что ваш код занял 15 минут только для ввода пяти строк?   -  person smci    schedule 17.09.2018


Ответы (1)


Можешь попробовать:

library(data.table)
library(reshape2)

dt = setDT(foo)[,seq(min(st)+5,max(et),5),.(userid,activity)]
dcast(dt, userid~V1, value.var='activity')
#  userid 5 10 15 20 25 30
#1      a x  x  x  x  y  y
#2      b z  z  z  z  z  x
person Colonel Beauvel    schedule 10.04.2015
comment
Спасибо - это хорошо работает. Все еще заинтересованы в любых улучшенных/более быстрых решениях с использованием dplyr и tidyr. Я нахожу их синтаксис более простым и понятным, хотя data.table в этом случае кажется немного быстрее. - person Bryan; 21.04.2015