You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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)

代码说明

  1. 时段标记:通过hour()提取小时数,判断当前时间属于白天还是夜间
  2. 总时段计算:将时间差转换为12小时为单位的完整时段数,反映从初始时间到当前的时段跨度
  3. 理论时段校验:根据初始时段和总时段数推导当前应属的时段,若与实际不符则说明跳过了中间时段
  4. 跳过调整:用cumsum()累计时段切换的次数,修正跳过时段导致的序号偏差
  5. 生成Rank:结合总时段数和调整值,得到每个时段的唯一序号

内容的提问来源于stack exchange,提问作者Polina B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:32:48