根据时间序列数据创建间隔

时间:2018-10-10 10:51:28

标签: r lubridate

我有一个用户和访问时间的数据框。可以重复访问。 我正在尝试创建给定时间间隔分组用户并命名为用户的用户列表,例如年。

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 

我的代码示例已经创建了按年份分组的用户列表。 我的问题是我需要用这种方法修改表,这对我的一百万个条目的表来说是个问题。

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 :(得分:2)

没有时间戳

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

答案 1 :(得分:1)

使用闪电般快速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

再次假设您的test $ 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的{​​{1}}中的子集用于“一次性”计算。

答案 2 :(得分:0)

您还可以按如下方式使用基本(统计)功能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)减去年份,而不必先转换为日期。

但是,如果您已经将timestamp列作为日期,只需替换您在尝试的解决方案中演示的lubridate::year()函数即可。