使用dplyr和lubridate生成日期时间时段分组序号
问题需求
需要将POSIXct类型的日期时间划分为**白天(6:00-17:59)和夜间(18:00至次日5:59)**两个时段,为每个连续的时段分配唯一序号。要求:
- 每个时段可包含任意行数
- 若出现跳过完整时段的情况(如当日白天直接衔接次日白天),跳过的时段也要算作不同序号,最终每个实际出现的时段对应唯一Rank
- 解决方案需要能融入dplyr工作流
数据示例
structure(list(SubDateTime = structure(c(1555187547, 1555194755, 1555231810, 1555573511, 1555664546, 1555702679, 1555704545, 1555706119, 1555707855, 1555709640, 1555713244, 1555722752, 1555753649, 1555837869 ), tzone = "UTC", class = c("POSIXct", "POSIXt"))), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -14L))
期望输出
SubDateTime Rank <dttm> <dbl> 1 2019-04-13 20:32:27 1 2 2019-04-13 22:32:35 1 3 2019-04-14 08:50:10 2 4 2019-04-18 07:45:11 3 5 2019-04-19 09:02:26 4 6 2019-04-19 19:37:59 5 7 2019-04-19 20:09:05 5 8 2019-04-19 20:35:19 5 9 2019-04-19 21:04:15 5 10 2019-04-19 21:34:00 5 11 2019-04-19 22:34:04 5 12 2019-04-20 01:12:32 5 13 2019-04-20 09:47:29 6 14 2019-04-21 09:11:09 7
解决方案
核心思路是先标记每个时间点的时段类型,再计算从初始时间到当前时间的完整时段数量,结合时段变化的累计值生成唯一序号,同时处理跳过时段的场景。
以下是可直接融入dplyr管道的代码:
library(dplyr) library(lubridate) df <- structure(list(SubDateTime = structure(c(1555187547, 1555194755, 1555231810, 1555573511, 1555664546, 1555702679, 1555704545, 1555706119, 1555707855, 1555709640, 1555713244, 1555722752, 1555753649, 1555837869 ), tzone = "UTC", class = c("POSIXct", "POSIXt"))), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -14L)) df_result <- df %>% # 标记时段:白天=1,夜间=0 mutate(period = ifelse(hour(SubDateTime) >= 6 & hour(SubDateTime) < 18, 1, 0)) %>% # 计算从初始时间到当前时间的完整12小时时段数 mutate(total_periods = floor(as.duration(SubDateTime - first(SubDateTime)) / dhours(12))) %>% # 获取初始时段类型 mutate(first_period = first(period)) %>% # 计算当前时间对应的理论时段类型 mutate(theoretical_period = (first_period + total_periods) %% 2) %>% # 累计时段变化次数,处理跳过时段的情况 mutate(skip_adjust = cumsum(abs(period - lag(period, default = first(period))))) %>% # 生成唯一Rank mutate(Rank = total_periods + skip_adjust + 1) %>% # 保留目标列 select(SubDateTime, Rank) print(df_result)
代码说明
- 时段标记:通过
hour()提取小时数,判断当前时间属于白天还是夜间 - 总时段计算:将时间差转换为12小时为单位的完整时段数,反映从初始时间到当前的时段跨度
- 理论时段校验:根据初始时段和总时段数推导当前应属的时段,若与实际不符则说明跳过了中间时段
- 跳过调整:用
cumsum()累计时段切换的次数,修正跳过时段导致的序号偏差 - 生成Rank:结合总时段数和调整值,得到每个时段的唯一序号
内容的提问来源于stack exchange,提问作者Polina B
相关产品推荐
相关产品推荐

