4. 数据预处理与标注:数据清洗、时间窗口分割与标签定义

大家好,我是你们的老朋友。今天咱们聊聊数据预处理和标注。说实话,很多做AI的朋友,一上来就急着调模型,结果数据质量不行,后面全白干。我在好几个项目里都吃过这个亏,所以今天把这部分经验掰开揉碎了讲给你听。

核心观点:数据预处理和标注,占整个AI项目工作量的60%以上。别不信,这是真的。

4.1 数据清洗:滤波与去趋势

传感器数据,说白了就是一堆带噪声的原始信号。你想想看,MCU采集到的加速度、温度、电流,哪个不是混着各种干扰?所以第一步,就是清洗。

4.1.1 滤波

滤波的目的很简单——把有用的信号留下,把没用的噪声滤掉。我个人习惯用两种方法:

  • 低通滤波:适合去除高频噪声。比如你采集人体运动数据,步频一般不超过5Hz,那50Hz的电源噪声就该滤掉。
  • 中值滤波:对付突发性的尖峰噪声特别管用。我在做工业设备振动监测时,经常遇到传感器被碰一下产生的大幅值毛刺,中值滤波一上,干净利落。

这里给个简单的滑动平均滤波代码,在MCU上跑起来很轻量:

// 滑动平均滤波,窗口大小N
#define N 10
float buffer[N];
int index = 0;

float moving_average(float new_sample) {
    static float sum = 0;
    static int count = 0;
    
    if (count < N) {
        sum += new_sample;
        buffer[index] = new_sample;
        index = (index + 1) % N;
        count++;
        return sum / count;
    } else {
        sum -= buffer[index];
        sum += new_sample;
        buffer[index] = new_sample;
        index = (index + 1) % N;
        return sum / N;
    }
}

小提示:窗口N选多大?经验值是信号主周期的2-5倍。比如你采集的步态信号周期约0.5秒,采样率100Hz,那N取100-250比较合适。

4.1.2 去趋势

去趋势,说白了就是把信号中的缓慢变化成分去掉。比如温度传感器,环境温度从早上到下午慢慢升高,这个趋势会掩盖你真正关心的振动细节。

我曾经在一个可穿戴设备项目里,没做去趋势,结果模型把温度漂移当成了用户活动,闹了大笑话。常用的方法有两种:

  • 差分法:简单粗暴,用当前值减去前一个值。适合实时处理。
  • 多项式拟合:精度高,但计算量大,适合离线分析。

4.2 时间窗口分割

原始数据是一长串时间序列,你不能直接扔给模型。为什么?因为模型需要看到一段“有意义”的片段。这就涉及到窗口分割。

4.2.1 固定窗口

固定窗口,就是一刀切。比如每256个采样点作为一个样本。优点是简单,缺点是可能把两个不同状态切到一个窗口里。

举个例子:你监测电机运行状态,正常转和异常振动可能就隔了0.1秒。固定窗口一划,两个状态混在一起,模型就懵了。

4.2.2 滑动窗口

滑动窗口更灵活。窗口长度固定,但每次只滑动一小步。比如窗口256点,步长32点。这样相邻窗口有大量重叠,信息冗余度高,模型学得更稳。

我建议你这样做:

  1. 先确定窗口长度:至少包含2-3个完整的事件周期。
  2. 再确定步长:一般是窗口长度的1/8到1/4。
  3. 最后做数据增强:滑动窗口天然就是数据增强,一个长序列能生成几十个样本。
// 滑动窗口分割伪代码
#define WINDOW_SIZE 256
#define STEP_SIZE 32

void sliding_window(float* data, int data_len) {
    int start = 0;
    int sample_id = 0;
    
    while (start + WINDOW_SIZE <= data_len) {
        // 取出 data[start] 到 data[start+WINDOW_SIZE-1] 作为一个样本
        extract_sample(data, start, WINDOW_SIZE, sample_id);
        start += STEP_SIZE;
        sample_id++;
    }
}

注意:滑动窗口会产生大量样本,MCU内存可能扛不住。建议在PC上预处理完,再把标注好的数据集烧录到设备上。

4.3 标签定义与标注策略

标签,就是告诉模型“这段数据是什么”。标签定义得好不好,直接决定模型能不能学会。

4.3.1 正常/异常分类

这是最简单的二分类。比如设备正常运转是0,出现故障是1。但这里有个坑——异常样本往往很少。我在做电机故障诊断时,正常数据几万条,异常数据只有几十条。

怎么办?两个思路:

  • 数据合成:人为制造一些异常模式,加进去。
  • 异常检测:用单分类模型,只学正常模式,偏离太多的就算异常。

4.3.2 多状态分类

现实场景中,设备往往有多个状态。比如:

状态 标签 描述
待机 0 设备上电但未运行
正常运行 1 额定负载下稳定运行
过载 2 负载超过额定值20%以上
故障 3 轴承磨损、转子不平衡等

标注时要注意:状态切换的过渡区,最好别标。比如从待机到正常运行,中间有1-2秒的过渡,这段数据直接扔掉,不然模型会学混乱。

我的经验:标注策略上,宁可少标,不要错标。我曾经为了凑样本量,把过渡区也标上了,结果模型准确率从92%掉到78%。后来花了三天重新清洗数据,才救回来。

4.4 本章知识体系

下面这张图,把本章的核心逻辑串起来了。你可以把它当作一个检查清单,做项目时对着来:

数据预处理与标注核心流程 原始传感器数据 数据清洗 滤波(低通/中值) + 去趋势(差分/拟合) 时间窗口分割 固定窗口 / 滑动窗口(重叠率75%~87.5%) 标签定义与标注 正常/异常分类 / 多状态分类(过渡区不标) 避坑指南 1. 滤波窗口选2-5倍信号周期 2. 去趋势别过度,会丢失低频信息 3. 滑动窗口步长别太大 4. 过渡区数据直接扔掉 5. 宁可少标,不要错标 6. MCU内存不够就PC预处理

嗯,以上就是数据预处理与标注的核心内容。说实话,这部分看起来琐碎,但做扎实了,后面模型训练会顺很多。我见过太多人在这上面翻车,希望你能少走弯路。

最后一个小建议:每次做数据预处理,都写一个处理日志。哪天模型效果不好,回头查日志,能快速定位问题。这个习惯救过我很多次。

专注资料整理