Создание интервалов из данных временных рядов - PullRequest
0 голосов
/ 10 октября 2018

У меня есть фрейм данных пользователей и времени доступа .Доступ раз может быть дублирован .Я пытаюсь создать список пользователей, сгруппированных с именем по заданному интервалу времени , например, год.

timestamp user
1  2013-03-06 01:00:00    1
2  2014-07-06 21:00:00    1
3  2014-07-31 23:00:00    2
4  2014-08-09 17:00:00    2
5  2014-08-14 20:00:00    2
6  2014-08-14 22:00:00    3
7  2014-08-16 15:00:00    3
8  2014-08-19 02:00:00    1
9  2014-12-28 18:00:00    1
10 2015-01-17 17:00:00    1
11 2015-01-22 22:00:00    2
12 2015-01-22 22:00:00    3
13 2015-03-23 15:00:00    4
14 2015-04-05 18:00:00    1
15 2015-04-06 01:00:00    2 

My пример кода уже создает список пользователей, сгруппированных по годам .Моя проблема в том, что мне нужно изменить таблицу в этом подходе, что становится проблемой для моих таблиц с миллионами записей .

test <- structure(list(timestamp = c("2013-03-06 01:00:00", "2014-07-06 21:00:00", 
                                 "2014-07-31 23:00:00", "2014-08-09 17:00:00", "2014-08-14 20:00:00", 
                                 "2014-08-14 22:00:00", "2014-08-16 15:00:00", "2014-08-19 02:00:00", 
                                 "2014-12-28 18:00:00", "2015-01-17 17:00:00", "2015-01-22 22:00:00", 
                                 "2015-01-22 22:00:00", "2015-03-23 15:00:00", "2015-04-05 18:00:00", 
                                 "2015-04-06 01:00:00"), user = c(1L, 1L, 2L, 2L, 2L, 3L, 3L, 
                                                                  1L, 1L, 1L, 2L, 3L, 4L, 1L, 2L)), .Names = c("timestamp", "user"
                                                                  ), class = "data.frame", row.names = c(NA, -15L))

require(lubridate)
#Creating "POSIXct" object from string timestamp
timestamp <- lapply(test$timestamp,
                function(x)parse_date_time(x, "y-m-d H:M:S"))
test$timestamp <- do.call(c,timestamp)
print(class(test$timestamp))

#Adding column for year
test <- cbind(test,sapply(timestamp, function(x)year(x)))
colnames(test)[3]<- "year"

#Creating list of year time intervals for users
intervals <- names(table(test$year))
users <- lapply(intervals, function(x)test[test$year %in% x,"user"])
names(users) <- intervals

Ответы [ 3 ]

0 голосов
/ 10 октября 2018

Вы также можете использовать базовую (статистическую) функцию aggregate() следующим образом:

aggregate( x = test$user, 
           by = list(year=substr(test$timestamp,1,4)), 
           FUN = unique ) 

Результат:

  year          x
1 2013          1
2 2014    1, 2, 3
3 2015 1, 2, 3, 4

Выше работало предположение, что ваш столбец меток времени изначально является простосимвольный вектор в точности так, как он включен в данные вашего структурированного примера.В этом случае вы можете напрямую подставить год с помощью substr(test$timestamp,1,4), избегая необходимости сначала преобразовывать в даты.

Однако, если у вас уже есть столбец отметки времени как дата, просто замените функцию lubridate::year(), которую выпродемонстрировано в вашей попытке решения.

0 голосов
/ 10 октября 2018

Другой вариант, использующий пакет с молниеносной быстротой data.table:

library(data.table)
setDT(test) # make `test` a data.frame 'by reference' (no copy is made at all)

test[, j=.(users=list(unique(user))),
       by=.(year=substr(test$timestamp,1,4))] 

   year   users
1: 2013       1
2: 2014   1,2,3
3: 2015 1,2,3,4

Снова предполагая, что ваш тестовый столбец $ timestamp является символьным вектором - в противном случае при необходимости замените lubridate :: year ().

Обновление:

Простое изменение, чтобы показать группировку вместо по месяцам (как это было упомянуто в комментарии):

 test[, j=.(users=list(unique(user))),
        by=.(ym=substr(test$timestamp,1,7))] 

        ym users
1: 2013-03     1
2: 2014-07   1,2
3: 2014-08 2,3,1
4: 2014-12     1
5: 2015-01 1,2,3
6: 2015-03     4
7: 2015-04   1,2

Или группировать по дням, чтобы помочь продемонстрировать, как подмножество ссцепление:

test[, j=.(users=list(unique(user))),
       by=.(ymd=substr(test$timestamp,1,11))][ymd>='2014-08-01' & ymd<= '2014-08-21']

           ymd users
1: 2014-08-09      2
2: 2014-08-14    2,3
3: 2014-08-16      3
4: 2014-08-19      1

Примечание для фильтрации / поднабора, если вас интересует только подмножество дат для расчета «одноразового» (и без сохранения всего агрегированного набора для хранения в других целях)вероятно, будет более эффективным сделать подмножество в i из DT[i, j, by] для вычисления «один раз».

0 голосов
/ 10 октября 2018

без отметок времени

трактует timestamp как символ.Работает только в том случае, если для каждой временной метки первые 4 цифры представляют год.

library(dplyr)
test %>%
  group_by( user, substr(timestamp,1,4 ) ) %>%
  summarise( )

#    user `substr(timestamp, 1, 4)`
#   <int> <chr>                    
# 1     1 2013                     
# 2     1 2014                     
# 3     1 2015                     
# 4     2 2014                     
# 5     2 2015                     
# 6     3 2014                     
# 7     3 2015                     
# 8     4 2015

dplyr + lubridate

извлечет год из отметки времени

library( dplyr )
library( lubridate )
test %>%
  mutate( timestamp = as.POSIXct( timestamp, format = "%Y-%m-%d %H:%M:%S" ) ) %>%
  group_by( user, lubridate::year( timestamp ) ) %>%
  summarise( )

# # Groups:   user [?]
#    user `year(timestamp)`
#   <int>             <dbl>
# 1     1              2013
# 2     1              2014
# 3     1              2015
# 4     2              2014
# 5     2              2015
# 6     3              2014
# 7     3              2015
# 8     4              2015

таблица

таблица частот также быстро создается

table( test$user, substr( test$timestamp, 1, 4 ) )

#   2013 2014 2015
# 1    1    3    2
# 2    0    3    2
# 3    0    2    1
# 4    0    0    1

есть еще другие варианты ... выберите один

отредактируйте

, если скорость - проблема, ty data.table

dcast( 
  setDT( test )[, timestamp :=  as.POSIXct( timestamp, format = "%Y-%m-%d %H:%M:%S" )][, .N, by = list( user, data.table::year(timestamp) )],
  user ~ data.table,
  value.var = "N")

#    user 2013 2014 2015
# 1:    1    1    3    2
# 2:    2   NA    3    2
# 3:    3   NA    2    1
# 4:    4   NA   NA    1
...