4、数据预处理技术:数据清洗(异常值、缺失值)、时间同步、重采样与归一化

各位同行,大家好。今天我们来聊聊数据预处理。

说实话,在风机数字孪生这个领域,我踩过最大的坑,不是算法选型,也不是模型调参,而是——数据本身。你想想看,一台风机每天产生的数据量动辄几十GB,但真正能用的,往往不到六成。为什么?因为现场的数据太“脏”了。

我个人习惯把数据预处理比作“做饭前的洗菜切菜”。菜不洗干净,再好的厨艺也白搭。下面我就把这套“洗菜”的功夫,掰开了揉碎了讲给你听。

数据预处理技术体系 原始数据 数据清洗 异常值 · 缺失值 时间同步 多源数据对齐 重采样 降采样 · 升采样 归一化 Min-Max · Z-score 干净数据 → 数字孪生

4.1 数据清洗:先把“垃圾”筛出去

数据清洗,说白了就是去掉那些明显不对劲的数据。我在项目里见过最离谱的情况——风速传感器报出-5m/s,温度传感器显示127℃。这种数据你要是直接喂给模型,模型会“疯掉”的。

4.1.1 异常值处理

异常值分两种:一种是物理上不可能的值,比如负风速;另一种是统计上的离群点,比如突然跳变到正常值的10倍。

我的经验法则:

  • 物理限值法:风速0~50m/s,功率0~额定功率×1.1,转速0~额定转速×1.2。超出直接剔除或置为NaN。
  • 3σ原则:对于正态分布的数据,超出均值±3倍标准差的值,标记为异常。我在东海某风场用过,效果不错。
  • IQR方法:四分位距法,适合非正态分布。Q1-1.5×IQR 到 Q3+1.5×IQR 之外的值,建议复查。

避坑指南:我曾经遇到过一个案例,某台风机连续3个月功率曲线异常,用3σ法筛掉了大量数据。后来发现是叶片结冰导致的真实性能下降——异常值不一定是“坏数据”,也可能是“故障信号”。所以,先问为什么,再动手删

4.1.2 缺失值处理

风机SCADA系统经常丢数据,原因很多:通讯中断、传感器故障、存储溢出。我统计过,一个典型风场的数据缺失率在3%~8%之间。

处理方式分几种:

  • 直接删除:缺失比例小于1%且随机分布时,可以删。但别超过总数据量的5%。
  • 前向填充:用上一个有效值填充。适合变化缓慢的变量,比如机舱温度。
  • 线性插值:用前后两个有效值做线性拟合。适合风速、功率这类连续变量。
  • 模型预测:用其他相关变量预测缺失值。比如用风速和转速预测功率缺失值。这个方法精度高,但计算量大。
# Python示例:缺失值处理
import pandas as pd
import numpy as np

# 读取数据
df = pd.read_csv('wind_turbine_data.csv', parse_dates=['timestamp'])

# 检查缺失率
missing_rate = df.isnull().sum() / len(df) * 100
print("各列缺失率:\n", missing_rate)

# 策略1:删除缺失率超过10%的列
df = df.drop(columns=df.columns[missing_rate > 10])

# 策略2:风速、功率用线性插值
df['wind_speed'] = df['wind_speed'].interpolate(method='linear')
df['active_power'] = df['active_power'].interpolate(method='linear')

# 策略3:机舱温度用前向填充
df['nacelle_temp'] = df['nacelle_temp'].fillna(method='ffill')

# 策略4:剩余少量缺失值用中位数填充
df = df.fillna(df.median())

4.2 时间同步:让所有数据“对表”

风机的数据来源五花八门:SCADA系统、CMS振动监测、气象塔、电网调度……这些系统的时间戳往往不一致。有的用UTC,有的用本地时间,有的甚至没有时间戳。

我记得有一次做某海上风场的数字孪生项目,SCADA数据和CMS数据差了整整8分钟。一开始没发现,结果模型训练出来,振动和功率的对应关系完全错位。后来花了整整两天重新对齐数据,教训深刻。

时间同步的要点:

  1. 统一时区:全部转为UTC,避免夏令时问题。
  2. 对齐时间戳:以SCADA系统的时间为基准,其他数据按最近邻原则对齐。
  3. 检查时间间隔:正常SCADA数据是10秒或1分钟一条。如果出现间隔突然变大(比如超过5分钟),说明有通讯中断,这段数据要标记。
  4. 处理延迟:有些传感器有响应延迟,比如温度传感器滞后风速变化约30秒。这个要在时间同步时补偿。
# Python示例:时间同步
# 假设SCADA数据是1分钟间隔,CMS数据是10秒间隔
scada = pd.read_csv('scada.csv', parse_dates=['time'])
cms = pd.read_csv('cms.csv', parse_dates=['time'])

# 将CMS数据重采样到1分钟,取平均值
cms_resampled = cms.set_index('time').resample('1T').mean()

# 按最近邻对齐
scada.set_index('time', inplace=True)
aligned = pd.merge_asof(scada, cms_resampled, 
                        left_index=True, right_index=True,
                        direction='nearest', tolerance=pd.Timedelta('30s'))

4.3 重采样:统一数据“节奏”

不同数据源的采样频率不一样。风速可能每秒采集一次,功率每10秒一次,温度每分钟一次。数字孪生模型需要统一的时间步长,这就得重采样。

重采样有两种方向:

  • 降采样:从高频到低频。比如把1秒数据降为1分钟数据。常用方法:均值、中位数、最大值(用于峰值分析)。
  • 升采样:从低频到高频。比如把1分钟数据升为10秒数据。常用方法:线性插值、样条插值、前向填充。

我的建议:

对于风机性能分析,我一般统一到10分钟间隔。为什么?因为IEC标准要求功率曲线测试用10分钟平均数据。而且10分钟能有效滤除湍流噪声,又不会丢失太多细节。

# Python示例:重采样到10分钟
df.set_index('timestamp', inplace=True)
df_10min = df.resample('10T').agg({
    'wind_speed': 'mean',
    'active_power': 'mean',
    'rotor_speed': 'mean',
    'pitch_angle': 'mean',
    'nacelle_temp': 'max'  # 温度取最大值,关注过热风险
})

4.4 归一化:让不同量纲的数据“平起平坐”

风速的单位是m/s,功率是kW,温度是℃,振动是mm/s。这些数值范围差异巨大——风速0~30,功率0~5000,温度-20~60。如果不做归一化,神经网络里大数值的变量会主导训练过程。

常用的归一化方法:

方法 公式 适用场景 注意事项
Min-Max归一化 x' = (x - min) / (max - min) 数据有明确上下界,如风速、功率 对异常值敏感,一个离群点会压缩其他数据
Z-score标准化 x' = (x - μ) / σ 数据近似正态分布,如振动幅值 不保证在[0,1]区间,可能有负值
Robust标准化 x' = (x - median) / IQR 数据含较多异常值 计算稍复杂,但抗干扰能力强

实战经验:我习惯对风速和功率用Min-Max归一化,因为它们的物理范围是已知的。对振动信号用Z-score,因为振动数据通常服从正态分布。对桨距角这种有明确物理意义的变量,我有时不做归一化——保留原始量纲反而更容易解释模型结果。

# Python示例:归一化
from sklearn.preprocessing import MinMaxScaler, StandardScaler

# Min-Max归一化(风速、功率)
scaler_mm = MinMaxScaler(feature_range=(0, 1))
df[['wind_speed', 'active_power']] = scaler_mm.fit_transform(
    df[['wind_speed', 'active_power']])

# Z-score标准化(振动)
scaler_std = StandardScaler()
df['vibration'] = scaler_std.fit_transform(df[['vibration']])

# 注意:保存scaler参数,用于后续逆变换
import joblib
joblib.dump(scaler_mm, 'scaler_wind_power.pkl')
joblib.dump(scaler_std, 'scaler_vibration.pkl')

4.5 预处理流程总结

好了,我们把整个流程串起来。我个人习惯按这个顺序走:

  1. 第一步:数据加载与概览——看看数据长什么样,缺失率、异常值、时间范围。
  2. 第二步:时间同步——统一时区,对齐时间戳,处理延迟。
  3. 第三步:数据清洗——先处理异常值(标记或剔除),再处理缺失值(插值或填充)。
  4. 第四步:重采样——统一到10分钟间隔,选择合适的聚合函数。
  5. 第五步:归一化——根据变量特性选择方法,保存scaler参数。
  6. 第六步:质量检查——画个分布图,看看处理后的数据是否合理。

最后提醒一句:预处理不是一劳永逸的。不同风场、不同机型、不同季节,数据的“脾气”都不一样。我每次拿到新数据,都会先花30%的时间做探索性分析,摸清数据的“性格”,再动手处理。磨刀不误砍柴工,这话在数据预处理上特别适用。


专注资料整理