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

如何归一化HHMM格式循环时间戳数值数据并移除异常值?

处理循环时间数据:异常值移除与归一化方案

一、先把数值型HHMM转成标准循环时间格式

你的数据是数值型且缺失前导零,第一步需要将其转换为可识别的循环时间结构:

  1. 将数值转为字符串,补前导零至4位:
    # 先简化列名方便操作
    colnames(sleepDiary_1)[3:4] <- c("bed_time", "sleep_attempt_time")
    
    # 补前导零到4位,统一格式
    sleepDiary_1$bed_time_str <- sprintf("%04d", sleepDiary_1$bed_time)
    sleepDiary_1$sleep_attempt_time_str <- sprintf("%04d", sleepDiary_1$sleep_attempt_time)
    
  2. 拆分小时和分钟,转换为总分钟数(范围0-1439,1440分钟等价于0,符合循环特性):
    # 提取小时、分钟并计算总分钟数
    sleepDiary_1$bed_time_mins <- as.integer(substr(sleepDiary_1$bed_time_str, 1, 2))*60 + 
                                  as.integer(substr(sleepDiary_1$bed_time_str, 3, 4))
    sleepDiary_1$sleep_attempt_time_mins <- as.integer(substr(sleepDiary_1$sleep_attempt_time_str, 1, 2))*60 + 
                                            as.integer(substr(sleepDiary_1$sleep_attempt_time_str, 3, 4))
    

二、异常值移除

睡眠时间的异常值需结合领域知识和循环数据特性处理:

  • 领域知识筛选:如果研究对象是普通白班人群,就寝/入睡时间通常集中在18:00(1080分钟)至次日08:00(480分钟),可先剔除不在该区间的数据:
    # 定义有效时间范围:18:00之后 或 08:00之前
    valid_bed <- sleepDiary_1$bed_time_mins >= 1080 | sleepDiary_1$bed_time_mins <= 480
    valid_sleep <- sleepDiary_1$sleep_attempt_time_mins >= 1080 | sleepDiary_1$sleep_attempt_time_mins <= 480
    
    # 筛选有效数据
    sleep_clean <- sleepDiary_1[valid_bed & valid_sleep, ]
    
  • 圆形统计法检测异常值:针对循环数据,用圆形均值和标准差判断偏离度,避免误判接近0/1440的点:
    1. 将分钟数转换为弧度(0到2π,对应1440分钟):
      sleep_clean$bed_rad <- (sleep_clean$bed_time_mins / 1440) * 2 * pi
      sleep_clean$sleep_rad <- (sleep_clean$sleep_attempt_time_mins / 1440) * 2 * pi
      
    2. 用circular包计算圆形统计量并剔除异常值:
      library(circular)
      # 转换为circular对象
      bed_circ <- circular(sleep_clean$bed_rad, type="angles", units="radians")
      # 计算圆形均值和标准差
      bed_mean <- mean(bed_circ)
      bed_sd <- sd(bed_circ)
      # 计算每个点到均值的循环距离,剔除超过3倍标准差的点
      bed_dist <- circular::distance(bed_circ, bed_mean)
      sleep_clean <- sleep_clean[bed_dist <= 3*bed_sd, ]
      

三、循环数据的归一化

普通的min-max、Z-score归一化不适合循环数据(会错误放大23:59和00:01的距离),推荐两种适配方案:

方案1:转换为正弦/余弦分量(最常用)

将时间映射为二维的正弦、余弦值,完整保留循环特性,适合多数后续分析:

# 基于总分钟数计算正弦、余弦值
sleep_clean$bed_sin <- sin(sleep_clean$bed_time_mins / 1440 * 2 * pi)
sleep_clean$bed_cos <- cos(sleep_clean$bed_time_mins / 1440 * 2 * pi)

sleep_clean$sleep_sin <- sin(sleep_clean$sleep_attempt_time_mins / 1440 * 2 * pi)
sleep_clean$sleep_cos <- cos(sleep_clean$sleep_attempt_time_mins / 1440 * 2 * pi)

比如23:59和00:01的正弦/余弦值非常接近,能正确反映实际时间差。

方案2:循环归一化到[-0.5, 0.5]

如果需要一维归一化值,可通过循环映射实现:

# 将0-1440分钟映射到[-0.5, 0.5]
sleep_clean$bed_norm <- ifelse(sleep_clean$bed_time_mins / 1440 > 0.5, 
                               (sleep_clean$bed_time_mins / 1440) - 1, 
                               sleep_clean$bed_time_mins / 1440)

sleep_clean$sleep_norm <- ifelse(sleep_clean$sleep_attempt_time_mins / 1440 > 0.5, 
                                 (sleep_clean$sleep_attempt_time_mins / 1440) - 1, 
                                 sleep_clean$sleep_attempt_time_mins / 1440)

此时23:00(1380分钟)会转为-0.0417,01:00(60分钟)转为0.0417,两者的距离符合实际2小时差距。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 00:47:54