如何为hms类型时间数据的30分钟间隔分箱添加友好标签?
解决cut函数生成时间分箱时的友好标签问题
我明白你遇到的困扰——用cut对时间数值分箱时,默认的科学计数法标签完全不直观,想自定义时间格式标签却没得到预期结果。咱们一步步来解决这个问题:
先回顾下你的场景
你有带时分信息的数据集,hour_min是hms对象,number是对应的秒数数值,已经加载了dplyr和lubridate。数据集结构如下:
library(dplyr) library(lubridate) df <- structure(list(hour_min = structure(c(NA, 69300, 46800, 35100, 52200, 37800, 52200, NA, 45300, 42300, NA, 29700, 46800, 34200, 32400, 43200, 36000, 41400, 29700, 36000), units = "secs", class = c("hms", "difftime")), number = c(NA, 69300, 46800, 35100, 52200, 37800, 52200, NA, 45300, 42300, NA, 29700, 46800, 34200, 32400, 43200, 36000, 41400, 29700, 36000)), class = "data.frame", row.names = c(NA, -20L), .Names = c("hour_min", "number"))
你尝试用这段代码添加自定义标签,但没得到友好的时间格式:
df$interval <- cut(df$number, breaks = seq(as.numeric(hms::as.hms("07:00:00")), as.numeric(hms::as.hms("23:00:00")), 1800), labels = as.character(seq(hms::as.hms("07:00:00"), as.hms("23:00:00"), 1800)))
而不指定labels时,得到的是可读性很差的科学计数法区间:
df %>% count(interval) # A tibble: 11 x 2 interval n <fct> <int> 1 (2.88e+04,3.06e+04] 2 2 (3.06e+04,3.24e+04] 1 3 (3.24e+04,3.42e+04] 1 4 (3.42e+04,3.6e+04] 3 5 (3.6e+04,3.78e+04] 1 6 (3.96e+04,4.14e+04] 1 7 (4.14e+04,4.32e+04] 2 8 (4.5e+04,4.68e+04] 3 9 (5.04e+04,5.22e+04] 2 10 (6.84e+04,7.02e+04] 1 11 <NA> 3
问题出在哪?
- 标签长度不匹配:
cut的breaks序列长度比需要的labels多1(比如32个breaks对应31个区间),你之前的labels用了和breaks一样长的序列,导致匹配错误。 - 时间格式未自定义:直接用
as.character()转换hms对象会保留秒数(比如"07:00:00"),不够简洁;而且没有生成区间式的标签(比如"07:00-07:30")。
修正后的解决方案
我们可以分步生成符合要求的标签:
# 1. 先生成分箱的数值断点(秒数) breaks_num <- seq( from = as.numeric(hms::as.hms("07:00:00")), to = as.numeric(hms::as.hms("23:00:00")), by = 1800 # 30分钟=1800秒 ) # 2. 生成友好的区间标签,格式为"起始时间-结束时间",只显示时分 labels_text <- paste0( # 取每个区间的起始时间,格式化为HH:MM format(hms::as.hms(breaks_num[-length(breaks_num)]), "%H:%M"), "-", # 取每个区间的结束时间,格式化为HH:MM format(hms::as.hms(breaks_num[-1]), "%H:%M") ) # 3. 用cut函数分箱并添加标签 df$interval <- cut( df$number, breaks = breaks_num, labels = labels_text, include.lowest = TRUE # 可选:确保第一个区间包含起始值 ) # 查看最终计数结果 df %>% count(interval)
最终效果
运行后你会得到类似这样的直观结果:
# A tibble: 11 x 2 interval n <fct> <int> 1 09:30-10:00 2 2 10:00-10:30 1 3 10:30-11:00 1 4 11:00-11:30 3 5 11:30-12:00 1 6 12:30-13:00 1 7 13:00-13:30 2 8 13:30-14:00 3 9 14:30-15:00 2 10 19:00-19:30 1 11 <NA> 3
这样标签就清晰易懂了,完全符合时间分箱的阅读习惯。
内容的提问来源于stack exchange,提问作者xhr489
相关产品推荐
相关产品推荐

