3、数据预处理基础:数据清洗、标准化与重采样
各位同行,大家好。我是老张,干风电运维这行有十几年了。今天咱们聊聊数据预处理。说实话,很多人觉得这步枯燥,不就是洗数据嘛。但我跟你说,这一步要是没做好,后面挖出来的全是垃圾。
我记得有一次,一个兄弟兴冲冲跑来说发现某台风机振动异常,结果我一查,是传感器掉线了,数据全是0。嗯,这就是典型的脏数据问题。所以,预处理不是走过场,是决定成败的关键。
3.1 数据清洗:把垃圾倒掉
数据清洗,说白了就是把那些「不靠谱」的数据揪出来。主要分两类:缺失值和异常值。
3.1.1 缺失值处理
风机SCADA系统里,缺失值太常见了。通讯中断、传感器故障、存储异常,都会导致数据断档。我个人习惯,先看看缺失比例。
- 缺失比例 < 5%:直接删除该行。简单粗暴,但有效。
- 缺失比例 5% - 20%:用插值法补全。比如线性插值、均值填充。
- 缺失比例 > 20%:这列数据基本废了。我建议直接扔掉,别心疼。
避坑指南:我曾经遇到一个项目,某台风机功率曲线异常。查了半天,发现是风速仪结冰导致数据缺失,但系统自动用前一天的均值填充了。结果呢?完全掩盖了结冰故障。所以,填充前一定要搞清楚缺失原因。
代码示例,用pandas处理缺失值:
import pandas as pd
import numpy as np
# 读取数据
df = pd.read_csv('wind_turbine_data.csv')
# 查看缺失情况
print(df.isnull().sum())
# 删除缺失比例超过20%的列
df = df.dropna(thresh=len(df)*0.8, axis=1)
# 线性插值填充
df['wind_speed'] = df['wind_speed'].interpolate(method='linear')
# 均值填充(慎用)
df['temperature'] = df['temperature'].fillna(df['temperature'].mean())
3.1.2 异常值处理
异常值比缺失值更隐蔽。你想想看,风机功率突然飙到3000kW,但额定功率才2000kW,这明显有问题。我常用的方法有几种:
- 3σ原则:超出均值±3倍标准差的数据,视为异常。
- 箱线图法:超出上下四分位数1.5倍IQR的数据,视为异常。
- 业务规则:比如风速不能为负,功率不能超过额定值。
我的经验:别完全依赖统计方法。有一次,箱线图把某台风机的正常停机数据标成了异常,差点误删。所以,一定要结合业务逻辑判断。
# 3σ法检测异常值
mean = df['power'].mean()
std = df['power'].std()
df_clean = df[(df['power'] > mean - 3*std) & (df['power'] < mean + 3*std)]
# 箱线图法
Q1 = df['power'].quantile(0.25)
Q3 = df['power'].quantile(0.75)
IQR = Q3 - Q1
df_clean = df[(df['power'] > Q1 - 1.5*IQR) & (df['power'] < Q3 + 1.5*IQR)]
3.2 数据标准化与归一化
为什么要做标准化?说白了,不同传感器的量纲不一样。风速是0-30m/s,温度是-20-50℃,功率是0-2000kW。如果不处理,模型会天然偏向数值大的特征。
我常用的两种方法:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score标准化 | x' = (x - μ) / σ | 数据近似正态分布,无上下界 |
| Min-Max归一化 | x' = (x - min) / (max - min) | 数据有明确上下界,如功率、温度 |
注意:归一化后数据会压缩到[0,1]区间。但如果有极端异常值,会把正常数据挤到很小范围。我建议先做异常值处理,再做归一化。
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Z-score标准化
scaler = StandardScaler()
df['power_scaled'] = scaler.fit_transform(df[['power']])
# Min-Max归一化
scaler = MinMaxScaler()
df['wind_speed_norm'] = scaler.fit_transform(df[['wind_speed']])
3.3 时间序列数据重采样
风机SCADA数据通常是秒级或分钟级采集。但做故障诊断时,我们往往不需要这么高的频率。重采样就是把高频数据降为低频,比如从1分钟降为10分钟。
为什么要这么做?
- 减少噪声:秒级数据抖动太大,掩盖了趋势。
- 降低计算量:10分钟一个点,数据量只有原来的1/10。
- 对齐不同数据源:有的传感器是1分钟,有的是5分钟,统一重采样才能一起分析。
我常用的重采样方法:
| 方法 | 说明 | 适用场景 |
|---|---|---|
| 均值重采样 | 取时间段内的平均值 | 功率、风速等平稳信号 |
| 最大值重采样 | 取时间段内的最大值 | 捕捉峰值,如振动冲击 |
| 最小值重采样 | 取时间段内的最小值 | 捕捉谷值,如低电压穿越 |
# 设置时间索引
df['timestamp'] = pd.to_datetime(df['timestamp'])
df = df.set_index('timestamp')
# 重采样为10分钟均值
df_10min = df.resample('10T').mean()
# 重采样为1小时最大值
df_1h = df.resample('1H').max()
# 重采样为1天最小值
df_1d = df.resample('1D').min()
我的习惯:做故障诊断时,我通常保留原始数据,同时生成多个重采样版本。比如,用10分钟均值看趋势,用1分钟最大值看冲击。不同尺度能发现不同问题。
3.4 本章知识体系
下面这张图,是我自己总结的数据预处理流程。你照着做,基本不会出大问题。
嗯,以上就是数据预处理的核心内容。你可能会问,这些方法够用吗?说实话,够用。但真正的高手,是在实践中不断调整参数、优化流程。我建议你拿自己场站的数据跑一遍,遇到问题再回来翻翻这章。