如何在R中对HH:MM格式的字符型时间进行用餐时段分类?
解决方案:HH:MM时间分类为用餐时段
核心问题分析
你之前的代码存在两个关键问题:
- 字符直接比较逻辑错误:字符串按字典序排序,比如
"23:00" > "04:59"会返回TRUE,但该时间实际属于Night时段,字符比较无法正确处理跨天的时间区间。 - POSIXct的日期时区干扰:
as.POSIXct会自动补充当前日期和时区,但你只需要时间的数值逻辑,完全可以避开这个问题。
方法1:转成当日分钟数进行分类(推荐)
将HH:MM格式的时间转换为从0点开始的分钟数(比如05:00=300分钟,23:59=1439分钟),用数值比较就能完全匹配时间逻辑,包括跨天的Night时段。
步骤1:优化时间提取(可选,提升效率)
原来的循环不断扩容向量效率较低,可改用sapply简化:
# 从lines[14:248]提取HH:MM格式的时间 Time <- sapply(lines[14:248], function(line) { date_time <- unlist(strsplit(line, split = "\t"))[1] unlist(strsplit(date_time, split = " "))[2] })
步骤2:转换为分钟数并分类
# 将每个HH:MM时间转为当日总分钟数 time_mins <- sapply(Time, function(t) { h_m <- as.integer(unlist(strsplit(t, ":"))) h_m[1] * 60 + h_m[2] }) # 用dplyr的case_when实现清晰的分类逻辑(需先加载dplyr包) library(dplyr) meal_type <- case_when( time_mins >= 300 & time_mins < 660 ~ "Breakfast", # 05:00-10:59 time_mins >= 660 & time_mins < 1020 ~ "Lunch", # 11:00-16:59 time_mins >= 1020 & time_mins < 1380 ~ "Dinner", # 17:00-22:59 time_mins >= 1380 | time_mins < 300 ~ "Night" # 23:00-04:59 ) # 若不用dplyr,用base R的ifelse链也可实现: meal_type <- ifelse(time_mins >= 300 & time_mins < 660, "Breakfast", ifelse(time_mins >= 660 & time_mins < 1020, "Lunch", ifelse(time_mins >= 1020 & time_mins < 1380, "Dinner", "Night")))
方法2:用POSIXct结合cut函数分类
给所有时间附加一个固定日期,转成POSIXct后通过断点划分时段,专门处理跨天的Night区间:
# 给时间附加固定日期,转成POSIXct格式 time_posix <- as.POSIXct(paste("2024-01-01", Time), format = "%Y-%m-%d %H:%M") # 定义时段断点(包含跨天的Night区间) breaks <- as.POSIXct(c("2024-01-01 00:00", "2024-01-01 05:00", "2024-01-01 11:00", "2024-01-01 17:00", "2024-01-01 23:00", "2024-01-02 00:00")) labels <- c("Night", "Breakfast", "Lunch", "Dinner", "Night") # 用cut函数完成分类 meal_type <- cut(time_posix, breaks = breaks, labels = labels, include.lowest = TRUE)
内容的提问来源于stack exchange,提问作者user21528954
相关产品推荐
相关产品推荐

