根据日期时间复制和修改行

时间:2020-09-14 17:09:20

标签: r datetime duplicates row rbind

我有一个像这样的data.table

library(dplyr)
library(data.table)

dt <- data.table(ID=c("A001","A002","A003","A004"),start_time=c('2019-06-18 05:18:00','2020-03-04 05:00:00',
                 '2019-05-10 19:00:00','2020-01-06 22:42:00'),end_time=c('2019-06-18 08:41:00','2020-03-04 05:04:00',
                 '2019-05-10 19:08:00','2020-01-07 03:10:00'))
 ID      

    start_time            end_time duration
1: A001 2019-06-18 05:18:00 2019-06-18 08:41:00 203 mins
2: A002 2020-03-04 05:59:00 2020-03-04 06:04:00   5 mins
3: A003 2019-05-10 19:00:00 2019-05-10 19:08:00   8 mins
4: A004 2020-01-06 22:42:00 2020-01-07 03:10:00 268 mins

持续时间简单地计算为

dt$start_time <- as.POSIXct(dt$start_time, tz='UTC')  
dt$end_time <- as.POSIXct(dt$end_time, tz='UTC')
dt <- dt %>% mutate(duration = (end_time-start_time))

我需要复制持续时间大于从start_time到小时结束的行(覆盖> 1小时的记录)。我需要为他们更改开始时间(小时的开始),结束时间-小时的结束时间或原始结束时间(如果是最后一行(最后观看时间))以及相应的持续时间,以便最终输出看起来像:

    dt_expected <- data.table(ID=c("A001","A001","A001","A001","A002","A002","A003","A004","A004","A004","A004","A004","A004"),
start_time=c('2019-06-18 05:18:00','2019-06-18 06:00:00','2019-06-18 07:00:00','2019-06-18 08:00:00', '2020-03-04 05:59:00', '2020-03-04 06:00:00',  '2019-05-10 19:00:00',
'2020-01-06 22:42:00', '2020-01-06 23:00:00','2020-01-07 00:00:00','2020-01-07 01:00:00','2020-01-07 02:00:00','2020-01-07 03:00:00'),
end_time=c('2019-06-18 05:59:00','2019-06-18 06:59:00','2019-06-18 07:59:00','2019-06-18 08:41:00','2020-03-04 05:59:00','2020-03-04 06:04:00',   '2019-05-10 19:08:00',    '2020-01-06 22:59:00','2020-01-06 23:59:00','2020-01-07 00:59:00','2020-01-07 01:59:00', '2020-01-07 02:59:00','2020-01-07 03:10:00'), 
duration = c(12,60,60,41,1,4,8,18,60,60,60,60,10)) 

请注意,ID为A002的记录也应重复,因为持续时间在2个不同小时内发生。

      ID          start_time            end_time duration
 1: A001 2019-06-18 05:18:00 2019-06-18 05:59:00       12
 2: A001 2019-06-18 06:00:00 2019-06-18 06:59:00       60
 3: A001 2019-06-18 07:00:00 2019-06-18 07:59:00       60
 4: A001 2019-06-18 08:00:00 2019-06-18 08:41:00       41
 5: A002 2020-03-04 05:59:00 2020-03-04 05:59:00        1
 6: A002 2020-03-04 06:00:00 2020-03-04 06:04:00        4
 7: A003 2019-05-10 19:00:00 2019-05-10 19:08:00        8
 8: A004 2020-01-06 22:42:00 2020-01-06 22:59:00       18
 9: A004 2020-01-06 23:00:00 2020-01-06 23:59:00       60
10: A004 2020-01-07 00:00:00 2020-01-07 00:59:00       60
11: A004 2020-01-07 01:00:00 2020-01-07 01:59:00       60
12: A004 2020-01-07 02:00:00 2020-01-07 02:59:00       60
13: A004 2020-01-07 03:00:00 2020-01-07 03:10:00       10

1 个答案:

答案 0 :(得分:0)

我认为这与您要寻找的非常接近。

这将创建新的开始和结束时间行,使用map中的purrr每小时创建一行。

然后,对于每个ID,它将使用start_time确定end_timepmin

首先,对于end_time,它花费该行的end_time与该行的start_time之后一个小时之间的最小值。例如,A001的第一行的end_time的时间为6:00,这是5:18到最接近的小时的ceiling_date时间,并且从{生成的序列中小于6:18 {1}}。对于A001的最后一行,map是8:41,小于9:00的end_time时间。

ceiling_date将采用最后一行的start_time和该行的end_time之间的最小值。例如,A001的第二行将具有6:00,这是start_time上方的行,该行小于end_time生成的序列中的6:18。

请注意,map的一行有0分钟-时间恰好是小时(19:00:00)。这些可以被过滤掉。

duration

输出

library(purrr)
library(dplyr)
library(tidyr)
library(lubridate)

dt %>%
  rowwise() %>%
  mutate(start_time = map(start_time, ~seq.POSIXt(., ceiling_date(end_time, "hour"), by = "hour"))) %>%
  unnest(start_time) %>%
  group_by(ID) %>%
  mutate(end_time = pmin(ceiling_date(start_time, unit = "hour"), end_time),
         start_time = pmin(floor_date(lag(end_time, default = first(end_time)), unit = "hour"), start_time),
         duration = difftime(end_time, start_time, units = "mins"))