3. 数据采集与预处理实战

异常检测算法的效果,往往在数据进入模型之前就已经被决定了。农业传感器现场采集到的原始数据几乎不可能直接使用:土壤湿度探头可能因接触不良出现长时间恒定值,空气温湿度传感器在清晨结露时读数漂移,网关断电会造成整段数据缺失,不同设备的上报周期不一致又导致多源数据无法逐点对齐。本节以一个温室环境监测场景为例,完整走一遍从原始数据到可用数据集的清洗、缺失值处理、时间对齐与归一化流程,并说明每一步的判断依据。

一、先看清数据长什么样

假设某温室部署了 6 个采集节点,每个节点上报空气温度、空气湿度、土壤含水率、光照强度四类指标,采样间隔标称为 5 分钟,数据以长表形式存储,字段包括 device_id、timestamp、metric、value。加载后第一件事不是急着清洗,而是做一次数据体检:统计每个设备每类指标的行数、时间跨度、缺失比例、取值范围和重复记录数。这一步能快速暴露三类问题——设备离线造成的整段缺失、指标本身的越界值、以及时间戳重复。

体检中常见的异常信号包括:某设备一天只有 12 条记录(应为 288 条),说明存在长时间离线;土壤含水率出现 120% 这样的读数,超出物理量程;同一时间戳出现两条不同数值,属于重复上报。把这些情况先记录成问题清单,再逐项处理,比盲目套用清洗函数更可靠。

二、数据清洗:处理重复、越界与恒定值

重复记录按 (device_id, timestamp, metric) 去重,保留最后一条或取均值,取决于业务语义;对传感器补传场景,通常保留最新上报值。越界值依据物理量程判断:空气温度合理区间取 -20~60 ℃,空气湿度 0~100%,土壤含水率 0~100%,光照强度 0~150000 lux。超出量程的读数应置为缺失而非直接截断,因为截断会人为制造出大量边界值,干扰后续异常检测对真实极值的识别。

恒定值是最容易被忽视的一类脏数据。土壤湿度探头脱落后可能连续数小时输出同一个数值,这类"卡死"数据在统计上表现为滑动窗口内标准差接近零。可用长度为 6(约 30 分钟)的滑动窗口计算标准差,当标准差小于阈值(如 0.01)且窗口内数值完全相同时,将该段标记为可疑并置为缺失。需要注意,夜间光照强度本就长期为 0,因此恒定值检测应排除光照这类天然存在零值段的指标,或仅在非零值段内判断。

清洗原则:能判定为"物理上不可能"的值置为缺失,能判定为"设备故障"的段置为缺失,其余可疑值保留但在数据集中增加标记列,交由异常检测模型自行判断,避免清洗阶段过度删除真实异常。

三、缺失值处理:区分短缺口与长缺口

缺失值不能一律插值。按缺口长度分层处理更合理:连续缺失不超过 3 个采样点(约 15 分钟)的短缺口,用线性插值或前向填充补齐,因为环境量在短时间内变化平缓;连续缺失超过 12 个点(约 1 小时)的长缺口,插值会凭空制造出平滑的虚假数据,应保留为缺失,并在后续建模时通过掩码或按设备剔除处理。

以空气温度为例,若 08:00 与 08:15 有值而中间两点缺失,线性插值即可;若某设备从 02:00 到 06:00 完全无数据,则整段保留缺失。插值后应回填一个 is_imputed 标记列,便于在异常检测阶段区分真实观测与补全值,避免把插值产生的平滑段误判为正常基准。

四、时间对齐:把多源数据放到同一时间轴上

不同设备的上报时刻存在秒级抖动,例如标称 5 分钟一次,实际可能是 10:00:03、10:05:11、10:09:58。时间对齐的做法是先把时间戳向下取整到 5 分钟栅格,再以该栅格为索引做重采样。对同一栅格内的多条记录取均值,对空栅格保留缺失。多指标数据需要先由长表透视为宽表,使每一行对应一个时间点、每一列对应一个指标,才能进行后续的逐列归一化与滑窗建模。

对齐时还要处理时区与夏令时问题,统一转换为本地标准时间并明确记录,避免跨季节数据出现一小时的整体偏移。对齐完成后应检查时间索引是否等间隔、是否存在重复索引,这是后续滑动窗口特征提取能否正确执行的前提。

原始长表 → 清洗 → 缺失分层 → 时间对齐 → 归一化 原始长表 device_id / timestamp metric / value 重复 · 越界 · 卡死 离线缺口 · 秒级抖动 数据清洗 去重:保留最新上报 越界:置为缺失 卡死:滑窗标准差 阈值 < 0.01 标记 缺失值分层 ≤3 点:线性插值 >12 点:保留缺失 回填 is_imputed 标记补全来源 时间对齐 向下取整 5 分钟 长表透视宽表 同栅格取均值 统一时区 归一化 Z-score Min-Max 按设备 分指标 时间对齐示意(设备 A 上报抖动 → 5 分钟栅格) 原始 10:00:03 10:05:11 10:09:58 10:20:07 10:25:02 10:35:09 栅格 10:00 10:05 10:10 10:15 10:20 10:25 10:30 10:35 浅色栅格 = 该时刻无上报,保留为缺失 归一化参数(均值 μ、标准差 σ 或 min/max)必须只用训练集统计量,验证集与测试集直接套用,防止数据泄漏。

五、归一化:参数只能来自训练集

四类指标量纲差异极大:温度约 15~35 ℃,湿度 30~95%,土壤含水率 10~45%,光照 0~80000 lux。若直接送入基于距离或梯度的异常检测算法,光照会主导距离计算。常用两种归一化:Z-score 将每列变换为均值 0、标准差 1,适合近似正态的温湿度;Min-Max 将数值压缩到 [0,1],适合光照这类有明确上下界的指标。对土壤含水率这类分布偏斜的指标,也可先做对数变换再标准化。

关键纪律是:均值、标准差、最大最小值等参数只能由训练集计算,然后原样应用到验证集和测试集。若对全量数据统一计算统计量,测试集的信息会泄漏进训练过程,导致异常检测的评估结果虚高。工程上通常把归一化器与模型一起保存,推理时加载同一组参数。

六、交付一份可复用的预处理配置

把上述决策固化成配置,能让同一套流程在不同批次数据上稳定复现。下面是一份可直接参考的配置样例,字段对应本节的处理逻辑:

preprocess:
  resample_interval: "5min"
  timezone: "Asia/Shanghai"
  dedup: keep_last
  range_check:
    air_temp:   [-20, 60]
    air_humid:  [0, 100]
    soil_moist: [0, 100]
    light:      [0, 150000]
  stuck_detect:
    window: 6
    std_threshold: 0.01
    exclude_metrics: [light]
  missing:
    short_gap_max: 3      # 线性插值
    long_gap_min: 12      # 保留缺失
    add_flag: is_imputed
  normalize:
    air_temp:   zscore
    air_humid:  zscore
    soil_moist: zscore
    light:      minmax
    fit_on: train_only

处理完成后,用几项指标验收:时间索引是否严格等间隔、各指标缺失比例是否在可接受范围、归一化后训练集均值是否接近 0、标准差是否接近 1、is_imputed 标记数量是否与预期缺口吻合。若某项不符,回到对应环节排查,而不是直接进入建模。经过这样一轮处理,数据集才具备支撑后续滑动窗口特征提取与异常检测建模的基本质量。