第三章 数据预处理与质量保障
数据预处理,说白了就是给风机数据「洗澡」。我干了这么多年风电运维,见过太多因为数据脏导致模型翻车的案例。你想想看,风机数据来自几十上百个传感器,温度、振动、转速、功率……哪个不出点幺蛾子?
这一章,我就把数据预处理的四个核心环节掰开揉碎讲清楚。嗯,都是我在项目里踩过的坑和攒下的经验。
3.1 缺失值处理
风机数据缺失太常见了。传感器故障、通讯中断、存储异常,随便一个原因就能让你数据表里多几个「窟窿」。我遇到过最夸张的一次,某风场SCADA系统宕机了整整6小时,回来一看,温度数据全没了。
缺失值处理,我一般分三步走:
- 先诊断——搞清楚缺失是随机的还是系统性的
- 再决策——是删、是补、还是留着
- 后执行——选对方法下手
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 本章知识体系
下面这张图,是我梳理的数据预处理全流程。你看一遍,基本就知道该从哪下手了。
数据预处理这件事,说难不难,说简单也不简单。我见过太多人把时间花在调模型上,结果数据预处理没做好,模型精度死活上不去。你想想看,垃圾进,垃圾出——这个道理在风电领域尤其适用。
好了,这一章的内容就到这里。记住:数据预处理不是「做完就行」,而是「做对才行」。多花点时间在数据上,模型会回报你的。