2、数据准备:数据采集策略(传感器、日志、合成数据),数据清洗与去噪,数据增强(裁剪、翻转、加噪)

说实话,做微小机器学习这么多年,我踩过最大的坑往往不是模型选错了,而是数据没准备好。你想想看,模型再牛,喂进去的是垃圾,吐出来的只能是更精致的垃圾。这一章,咱们就聊聊数据准备那些事儿。

2.1 数据采集策略

数据从哪来?这问题听起来简单,但实际做起来门道不少。我一般把数据来源分成三类:传感器、日志、合成数据。每种都有各自的脾气。

2.1.1 传感器数据采集

传感器是TinyML最常用的数据源。加速度计、麦克风、温度传感器……这些小家伙每天都在产生海量数据。

采集要点:

  • 采样率要匹配:别盲目追求高采样率。我记得有次做手势识别,用了200Hz的加速度计采样,结果模型跑在MCU上根本扛不住。后来降到50Hz,效果反而更稳。
  • 多场景覆盖:别只在实验室里采。我习惯让设备在不同温度、不同光照、不同摆放角度下跑一遍。你想想看,用户可不会像你一样把传感器端端正正放桌上。
  • 标注要同步:传感器数据是时间序列,标注时一定要对齐时间戳。我曾经因为时间戳没对齐,白费了两周功夫。
我的小技巧: 采集传感器数据时,我会同时录一段视频。回头标注的时候,视频能帮你回忆起当时发生了什么。这招救过我很多次。

2.1.2 日志数据采集

日志数据,说白了就是系统运行过程中留下的痕迹。比如设备上报的状态、用户的操作记录、异常事件等。

采集策略:

  • 结构化存储:别把日志写成散文。我习惯用JSON格式,字段名统一、类型明确。这样后面清洗起来省心很多。
  • 保留原始时间戳:日志里的时间戳千万别自作主张格式化。保留Unix时间戳,后面做时序分析时最灵活。
  • 注意隐私:这个我得特别提醒。日志里可能包含用户敏感信息,采集前一定要做脱敏处理。嗯,这里要注意,合规问题不是闹着玩的。

2.1.3 合成数据

有时候真实数据不够,或者某些极端场景根本采不到。这时候就得靠合成数据了。

我做过一个项目,需要检测设备跌落。总不能真把设备摔几百次吧?于是我用物理引擎模拟了各种跌落角度、高度、地面材质,生成了上万条数据。

合成数据生成方法:

  • 物理仿真:用Unity、Gazebo等工具模拟传感器输出
  • 数据插值:在真实数据之间做线性或样条插值
  • GAN生成:用生成对抗网络产生逼真的合成样本
注意: 合成数据不能完全替代真实数据。我建议合成数据占比不要超过30%,而且一定要用真实数据做最终验证。否则模型在仿真环境里跑得飞起,一到现实就翻车。

2.2 数据清洗与去噪

数据采回来了,但别急着用。原始数据里什么妖魔鬼怪都有。我习惯先做一轮清洗,把明显有问题的数据剔除掉。

2.2.1 常见数据问题

问题类型 表现 处理方法
缺失值 某段时间数据为空 插值填充或直接丢弃
异常值 数值远超正常范围 3σ原则或IQR方法剔除
重复数据 完全相同的数据出现多次 去重,保留第一条
时间戳错乱 时间顺序颠倒或跳跃 按时间戳重排序

2.2.2 去噪方法

传感器数据天生带噪。我常用的去噪手段有这些:

  • 移动平均滤波:简单有效,适合平滑抖动。窗口大小我一般取3-5个点。
  • 中值滤波:对付椒盐噪声特别好。我做过一个按键检测项目,传感器偶尔会蹦出个离谱值,中值滤波一把就搞定了。
  • 低通滤波:用一阶RC滤波器,适合去除高频噪声。代码实现就一行:y = alpha * x + (1 - alpha) * y_prev
// 一阶低通滤波示例
float lowpass_filter(float input, float prev_output, float alpha) {
    return alpha * input + (1.0f - alpha) * prev_output;
}
// alpha取值0.1~0.3效果较好,具体看你的采样率
核心原则: 去噪要适度。别把信号本身的特征也滤掉了。我习惯先可视化看看噪声的频谱分布,再决定用什么滤波器。

2.3 数据增强

数据不够?增强来凑。数据增强说白了就是「无中生有」,但得有章法。

2.3.1 裁剪(Cropping)

对于时间序列数据,裁剪就是从长序列里随机截取一段。比如你有一段10秒的加速度数据,可以随机裁剪出2秒的片段。

我的做法:

  • 固定窗口长度,比如128个采样点
  • 从原始数据中随机取起始位置
  • 保证裁剪后的片段包含完整的动作特征

为什么会这样?因为模型如果只见过固定长度的输入,遇到不同长度的真实数据就容易懵。裁剪增强能让模型学会「只看关键部分」。

2.3.2 翻转(Flipping)

翻转不是只能用在图像上。对于传感器数据,翻转同样有效。

  • 时间翻转:把时间序列倒过来。比如「左挥手」倒过来就是「右挥手」?不一定,但能增加数据多样性。
  • 数值翻转:把加速度值取反。比如设备朝上变成朝下,这个在对称场景下很管用。
注意: 翻转要符合物理意义。别把「向上」翻转成「向下」后,还当「向上」来训练。我一般会在翻转后重新检查标注。

2.3.3 加噪(Adding Noise)

给数据加点噪声,能让模型更鲁棒。说白了就是让模型见过「世面」,不至于被一点小干扰就带偏。

常用加噪方式:

  • 高斯噪声:均值为0,标准差取信号幅值的1%-5%
  • 椒盐噪声:随机把某些点置为最大值或最小值
  • 抖动:对时间轴做微小偏移,模拟采样时钟的不稳定
// 添加高斯噪声示例
float add_gaussian_noise(float signal, float noise_level) {
    // noise_level 一般取0.01~0.05
    float noise = (float)rand() / RAND_MAX * 2.0f - 1.0f;
    return signal + noise * noise_level;
}
避坑指南: 我曾经在一个震动检测项目里加了太多噪声,结果模型把噪声当成了特征。后来我学乖了:加噪后的数据一定要可视化看看,确保信号特征依然清晰可辨。

好了,数据准备这块就聊到这儿。记住一句话:数据质量决定了模型的天花板,算法只是逼近这个天花板的手段。下一章咱们聊聊模型选型,到时候见。