如何在R中排除非业务时段(上周五18点至本周一8点)计算actual_tat?
问题描述
现有如下R数据框:
library(dplyr) library(lubridate) ticket_id <- c("id_1234","id_2234","id_1334","id_1244","id_1294", "id_1264","id_1634","id_1734","id_1834","id_1934") created <- c("2024-09-22 22:00:00","2024-09-21 23:00:00","2024-09-19 11:30:00","2024-09-23 6:00:00","2024-09-20 18:30:00", "2024-09-15 10:00:00","2024-09-14 23:00:00","2024-09-11 5:30:00","2024-09-16 7:30:00","2024-09-13 19:27:00") tat <- c(14.4, 38, 106, 6.4, 64, 29, 37, 129.5, 2.8, 66) df.sample <- data.frame(ticket_id,created,tat,stringsAsFactors=FALSE) df.sample$created <- ymd_hms(df.sample$created) df.sample$tat = as.numeric(df.sample$tat)
需要新增actual_tat列,计算规则:
- 若工单创建时间处于上周五18:00至本周一08:00的非业务时段,从
tat中排除创建时间到本周一08:00的时长(若tat小于该排除时长,则actual_tat为0); - 若创建时间不在该时段内,
actual_tat与tat值相同。
示例:工单创建于周日7:00,tat为14小时,则actual_tat为1小时(14-13,即周一08:00之后的时长)。
尝试的代码未得到正确结果,期望输出为:
ticket_id created tat actual_tat 1 id_1234 2024-09-22 22:00:00 14.4 4.4 2 id_2234 2024-09-21 23:00:00 38.0 5.0 3 id_1334 2024-09-19 11:30:00 106.0 106.0 4 id_1244 2024-09-23 06:00:00 6.4 4.4 5 id_1294 2024-09-20 18:30:00 64.0 2.5 6 id_1264 2024-09-15 10:00:00 29.0 7.0 7 id_1634 2024-09-14 23:00:00 37.0 4.0 8 id_1734 2024-09-11 05:30:00 129.5 129.5 9 id_1834 2024-09-16 07:30:00 2.8 2.3 10 id_1934 2024-09-13 19:27:00 66.0 5.5
解决方案
你的代码核心问题在于周一08:00基准点的计算错误,以及依赖星期标签(如"Fri")可能受系统语言影响。以下是修正后的代码:
df.sample %>% mutate( # 用数字判断星期几(1=周一,7=周日),避免语言依赖 wday_num = wday(created, week_start = 1), hour_num = hour(created), # 计算需要排除的时段终点:创建时间之后的第一个周一08:00 exclude_end = case_when( # 周一00:00-08:00:当天08:00 wday_num == 1 & hour_num < 8 ~ floor_date(created, "day") + hours(8), # 周五18:00及以后、周六、周日:下周一08:00 (wday_num == 5 & hour_num >= 18) | wday_num %in% c(6,7) ~ floor_date(created, "week", week_start = 1) + weeks(1) + hours(8), # 其他情况:不属于非业务时段,设为NA TRUE ~ NA_POSIXct_ ), # 计算需要排除的时长(小时) exclude_hours = as.numeric(difftime(exclude_end, created, units = "hours")), # 计算actual_tat:排除非业务时段,确保结果不小于0 actual_tat = case_when( !is.na(exclude_hours) ~ pmax(tat - exclude_hours, 0), TRUE ~ tat ) ) %>% # 保留原列和结果列,移除中间计算列(可选) select(ticket_id, created, tat, actual_tat)
代码说明
- 星期判断:用
wday(..., week_start=1)将周一设为星期1,避免系统语言对标签的影响,判断更可靠。 - 排除时段终点计算:
- 周一早8点前创建的工单,排除到当天8点;
- 周五晚6点后、周六、周日创建的工单,排除到下周一8点;
- 时长计算:用
difftime计算创建时间到排除终点的小时数,再用pmax确保actual_tat不会为负数。 - 结果整理:可选移除中间计算列,保留需要的字段。
运行上述代码后,即可得到你期望的输出结果。
内容的提问来源于stack exchange,提问作者Sharath
相关产品推荐
相关产品推荐

