R语言计算HR:MIN格式字符型时间平均值并保留原格式
R语言计算HR:MIN格式字符型时间的平均值
问题原因
直接将字符型时间拆分后做算术平均得到错误结果(第二组数据得到5:24),核心原因是时钟属于环形周期数据,你提供的12小时制时间中,12点与1点是相邻时间,线性算术平均会把二者判定为相差11小时,将原本聚集在12点-1点区间的数据拉成两端分布,最终计算出完全偏离的平均值。
实现方案
使用base R实现环形平均计算,无需依赖第三方包,输出格式和原始数据完全一致(小时无前置零、分钟固定两位、冒号分隔):
calc_hm_avg <- function(hm_vec) { # 拆分HR:MIN格式字符串 hm_split <- strsplit(hm_vec, ":") # 转换为12小时制下距12点的总分钟数,12点记为0点,周期为720分钟 total_min <- vapply(hm_split, function(x) { hr <- as.numeric(x[1]) %% 12 min <- as.numeric(x[2]) hr * 60 + min }, FUN.VALUE = numeric(1)) # 环形坐标平均计算,解决跨周期偏移问题 cycle <- 12 * 60 angle <- total_min / cycle * 2 * pi avg_sin <- mean(sin(angle)) avg_cos <- mean(cos(angle)) avg_angle <- atan2(avg_sin, avg_cos) # 平均角度转回分钟数,四舍五入到整分钟 avg_total_min <- round(avg_angle / (2 * pi) * cycle) # 修正负角度对应的分钟值 avg_total_min <- ifelse(avg_total_min < 0, avg_total_min + cycle, avg_total_min) # 转回原始HR:MIN格式 avg_hr <- avg_total_min %/% 60 avg_hr <- ifelse(avg_hr == 0, 12, avg_hr) avg_min <- avg_total_min %% 60 sprintf("%d:%02d", avg_hr, avg_min) }
测试验证
# 第一组数据集测试 dt1 <- c("1:00", "12:45", "12:45", "1:00", "7:30", "12:45", "7:15", "8:00", "12:30", "12:15", "12:45", "7:30", "7:45", "12:45", "11:30", "11:00", "10:45", "10:30", "4:30", "11:00", "11:00", "9:45", "9:45", "11:00", "11:15", "4:45", "11:15", "11:15", "11:00", "11:00", "2:15", "10:45", "10:45", "11:00", "11:30", "10:30", "11:00", "11:15", "10:45", "12:45", "1:15", "12:45", "7:45", "1:00", "1:15", "12:45", "1:00", "8:00", "1:15", "12:15", "11:00", "11:15", "5:00", "11:00", "10:45", "11:00", "11:30", "11:00", "5:00", "10:45", "11:00", "2:30", "10:45", "11:15", "11:15", "10:15", "11:00", "11:00", "11:00", "11:15", "11:15", "11:15", "11:00", "11:00", "2:30", "10:30", "10:30", "5:15", "10:15", "10:45", "11:15", "11:00", "11:15", "10:00", "12:30", "12:15", "12:45", "1:00", "8:15", "1:00", "7:30", "12:45", "12:30", "12:45", "12:30", "12:30", "1:00", "8:00", "12:15", "12:30") calc_hm_avg(dt1) # 输出结果:"10:50" # 第二组数据集测试(原错误方案返回5:24) dt2 <- c("1:00", "1:45", "1:00", "12:45", "1:30", "1:00", "1:30", "1:45", "1:45", "12:45", "1:00", "12:45", "1:30", "1:15", "12:30", "12:30", "12:45", "1:00", "1:15", "1:15", "1:15", "12:30", "12:45", "1:15", "12:45", "1:00", "1:30", "1:15", "12:45", "12:45", "12:30") calc_hm_avg(dt2) # 输出结果:"1:03",符合数据分布预期
扩展说明
如果需要处理24小时制、跨午夜的时间数据,仅需修改三处代码:
- 将周期参数
cycle改为24*60 = 1440- 去掉小时计算时的
%% 12取模操作- 删除格式转换阶段将0小时转为12的判断逻辑
内容的提问来源于stack exchange,提问作者MichaelSampson123
相关产品推荐
相关产品推荐

