第三章 数据预处理与质量保障

数据预处理,说白了就是给风机数据「洗澡」。我干了这么多年风电运维,见过太多因为数据脏导致模型翻车的案例。你想想看,风机数据来自几十上百个传感器,温度、振动、转速、功率……哪个不出点幺蛾子?

这一章,我就把数据预处理的四个核心环节掰开揉碎讲清楚。嗯,都是我在项目里踩过的坑和攒下的经验。

3.1 缺失值处理

风机数据缺失太常见了。传感器故障、通讯中断、存储异常,随便一个原因就能让你数据表里多几个「窟窿」。我遇到过最夸张的一次,某风场SCADA系统宕机了整整6小时,回来一看,温度数据全没了。

缺失值处理,我一般分三步走:

  1. 先诊断——搞清楚缺失是随机的还是系统性的
  2. 再决策——是删、是补、还是留着
  3. 后执行——选对方法下手

3.1.1 缺失类型判断

缺失类型 典型场景 处理建议
完全随机缺失 传感器偶尔闪断 可删除或简单插补
随机缺失 温度高时振动传感器失效 需用模型预测填补
非随机缺失 停机期间数据全部缺失 必须结合工况处理

我个人习惯,先用isnull().sum()扫一遍,再画个缺失热力图。如果缺失率超过30%,我会直接放弃这个特征——补出来的东西,你敢信吗?

3.1.2 常用填补方法

填补方法我按「无脑程度」排个序:

  • 均值/中位数填补——最简单,但会降低方差。我只在缺失率低于5%时用
  • 前向/后向填充——时间序列数据首选。比如风速数据,前一秒的值和后一秒差不了多少
  • 线性插值——比前向填充更平滑。我处理齿轮箱油温时常用
  • KNN填补——找相似样本的平均值。计算量大,但效果不错
  • 模型预测填补——用随机森林或XGBoost预测缺失值。精度最高,也最耗时

我的经验:风机振动数据千万别用均值填补!振动信号本身就有波动性,一填补就把故障特征抹平了。我曾经吃过这个亏,模型死活检测不出轴承早期故障,后来才发现是填补方法选错了。

# 前向填充示例
df['wind_speed'].fillna(method='ffill', inplace=True)

# 线性插值
df['temperature'].interpolate(method='linear', inplace=True)

3.2 异常值检测与清洗

异常值,说白了就是「不对劲」的数据。风机功率突然飙到额定值的150%,风速显示负值,振动幅值一夜之间翻了三倍……这些我都见过。

异常值分两种:一种是真异常(传感器坏了),一种是假异常(风机确实在特殊工况下运行)。区分这两者,是数据清洗的核心。

3.2.1 检测方法

我常用的方法就三个,够用:

  • 3σ原则——正态分布数据,超过均值±3倍标准差的就是异常。简单粗暴,但遇到偏态分布就抓瞎
  • 箱线图法——用四分位数判断。不受极端值影响,我处理功率数据时最爱用
  • 孤立森林——机器学习方法。高维数据效果好,但需要调参

避坑指南:我曾经用3σ原则清洗风速数据,结果把台风天的真实数据全删了。后来模型预测极端天气下的发电量,偏差大得离谱。记住:异常≠错误,先搞清楚原因再动手。

# 箱线图法检测异常
Q1 = df['power'].quantile(0.25)
Q3 = df['power'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['power'] < lower_bound) | (df['power'] > upper_bound)]

3.2.2 清洗策略

检测出异常值后,怎么处理?我的原则是:

  • 传感器故障导致的异常——直接删除或标记为缺失
  • 工况变化导致的异常——保留,但打上标签
  • 无法判断的异常——先标记,后续结合运维日志确认

注意:千万别一股脑全删了!异常值里可能藏着故障前兆。我有个同事把变桨系统卡涩前的异常振动数据全洗掉了,结果模型完全没预警,最后桨叶直接打坏了。

3.3 数据归一化与标准化

为什么要归一化?你想想看,风速是0-30m/s,振动是0-100mm/s,功率是0-2000kW。这些量纲都不一样,扔进模型里,数值大的特征就会主导训练过程。

说白了,归一化和标准化就是把数据拉到同一个「频道」上。

3.3.1 归一化(Min-Max Scaling)

把数据压缩到[0,1]区间。公式很简单:

X_norm = (X - X_min) / (X_max - X_min)

我一般在做神经网络时用归一化。但要注意,如果数据里有极端值,归一化后大部分数据会被挤到一个小区域里,效果反而不好。

3.3.2 标准化(Z-score Scaling)

把数据变成均值为0、标准差为1的分布。公式:

X_std = (X - μ) / σ

标准化对异常值没那么敏感,我处理振动数据时首选标准化。尤其是做PCA降维之前,标准化是必须的。

我的习惯:如果后续要用树模型(随机森林、XGBoost),其实不用归一化或标准化。树模型基于分裂点,不受量纲影响。但如果是神经网络、SVM、KNN,必须做!

from sklearn.preprocessing import MinMaxScaler, StandardScaler

# 归一化
scaler = MinMaxScaler()
df_norm = scaler.fit_transform(df[['wind_speed', 'power']])

# 标准化
scaler = StandardScaler()
df_std = scaler.fit_transform(df[['vibration', 'temperature']])

3.4 时间序列重采样技术

风机数据采样频率五花八门。SCADA系统一般是10分钟一条,振动监测可能是每秒几千次,CMS系统又是每小时一个报告。要把这些数据对齐,就得靠重采样。

重采样说白了就是「改节奏」——把高频数据降下来,或者把低频数据提上去。

3.4.1 降采样(Downsampling)

从高频到低频。比如把1秒的振动数据降成10分钟的平均值。我常用的聚合方式:

  • 均值——最常用,但会丢失波动信息
  • 最大值/最小值——捕捉极端情况
  • 标准差——反映波动程度
  • 均方根——处理振动信号时必用

3.4.2 升采样(Upsampling)

从低频到高频。比如把10分钟的SCADA数据插值成1分钟一条。升采样不会增加信息量,只是让数据看起来更「密」。

避坑指南:我曾经把10分钟的功率数据升采样成1分钟,然后用这个「假数据」做功率预测。结果模型精度看起来很高,一上线就崩了。为什么?因为升采样引入的平滑效应,让模型误以为数据很规律。记住:升采样只改变密度,不改变信息量。

# 降采样:10分钟均值
df_resampled = df.resample('10T').mean()

# 升采样:线性插值
df_resampled = df.resample('1T').interpolate(method='linear')

3.5 本章知识体系

下面这张图,是我梳理的数据预处理全流程。你看一遍,基本就知道该从哪下手了。

数据预处理与质量保障流程 原始数据 缺失值处理 异常值检测与清洗 归一化与标准化 时间序列重采样 关键决策点 • 缺失率<5%:直接删除 • 缺失率5-30%:插补 • 缺失率>30%:放弃特征 • 异常值先判断原因 • 树模型不用归一化 • 神经网络必须归一化 • 降采样用均值/RMS • 升采样用线性插值 • 升采样不增加信息量

数据预处理这件事,说难不难,说简单也不简单。我见过太多人把时间花在调模型上,结果数据预处理没做好,模型精度死活上不去。你想想看,垃圾进,垃圾出——这个道理在风电领域尤其适用。

好了,这一章的内容就到这里。记住:数据预处理不是「做完就行」,而是「做对才行」。多花点时间在数据上,模型会回报你的。


专注资料整理