首页 > 解决方案 > 基于日期时间复制和修改行

问题描述

我有一个看起来像这样的 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

标签: rdatetimeduplicatesrowrbind

解决方案


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

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

然后,对于每个ID,它将确定start_timeend_time使用pmin

首先,对于,它取该行和比该行晚一小时end_time之间的最小值。例如,A001 的第一行将是 6:00,这是5:18 到最接近小时的时间,并且从生成的序列中小于 6:18 。对于 A001 的最后一行,是 8:41,小于9:00 的时间。end_timestart_timeend_timeceiling_datemapend_timeceiling_date

将取最后一行和该行start_time之间的最小值。例如,A001 的第二行将有 6:00,这是上面的行,它小于从 生成的序列的 6:18 。end_timestart_timeend_timemap

请注意,一行有 0 分钟duration- 时间正好落在整点 (19:00:00)。这些可以被过滤掉。

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"))

输出

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

推荐阅读