第四章:数据预处理技术——风电功率预测的“地基工程”

各位工程师朋友,咱们今天聊聊数据预处理。说实话,这活儿看着不起眼,但我在风电行业摸爬滚打这么多年,可以负责任地告诉你:预测模型的效果,七成靠数据,三成靠算法。你想想看,一堆脏数据、乱数据扔进模型,再牛的算法也白搭。

核心观点:数据预处理不是“洗菜”,而是“炼钢”。原始数据里藏着大量噪声、异常和缺失,不处理干净,后面的预测就是空中楼阁。

数据预处理技术 异常值检测与处理 缺失值插补 数据归一化与标准化 时间序列重采样 3σ准则 IQR方法 线性插值 前向填充 Min-Max归一化 Z-score标准化 降采样 升采样

4.1 异常值检测与处理——揪出数据里的“捣蛋鬼”

我在风电场调试那会儿,遇到过一件特邪门的事。某台风机功率曲线看着挺正常,可一到凌晨3点,功率就突然跳变到负值。后来一查,是数据采集卡接触不良。这就是典型的异常值。

异常值怎么找?我个人习惯用两种方法:

4.1.1 3σ准则(拉依达准则)

说白了,就是假设数据服从正态分布。超出均值±3倍标准差的数据,就视为异常。这个方法简单粗暴,但有个前提——数据得大致符合正态分布。风电功率数据嘛,有时候偏态严重,用这个就得小心了。

import numpy as np
import pandas as pd

def detect_outliers_3sigma(data, column):
    mean = data[column].mean()
    std = data[column].std()
    lower_bound = mean - 3 * std
    upper_bound = mean + 3 * std
    outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]
    return outliers

# 示例:检测风速异常值
wind_data = pd.read_csv('wind_speed.csv')
outliers = detect_outliers_3sigma(wind_data, 'wind_speed')
print(f"检测到 {len(outliers)} 个异常值")

4.1.2 IQR方法(四分位距法)

这个方法更稳健,不受极端值影响。它用Q1(25%分位数)和Q3(75%分位数)来定义正常范围。超出1.5倍IQR的,就算异常。

def detect_outliers_iqr(data, column):
    Q1 = data[column].quantile(0.25)
    Q3 = data[column].quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]
    return outliers

我的经验:处理异常值时,别一删了之。我曾经遇到一批数据,异常值占了5%,但仔细分析后发现,这些“异常”其实是风机在极端天气下的真实出力。所以,先分析原因,再决定是剔除、修正还是保留。

4.2 缺失值插补——给数据“补窟窿”

风电数据缺失太常见了。通信中断、传感器故障、维护停机……原因五花八门。你想想看,如果缺失率超过20%,直接删掉行,那损失的信息量可就大了。

我常用的插补方法有这几种:

方法 适用场景 优点 缺点
前向填充(ffill) 短时间缺失(<5个点) 简单快速,保持趋势 长时间缺失会“平头”
后向填充(bfill) 数据开头缺失 同上 同上
线性插值 连续型变量,变化平缓 平滑过渡,符合物理规律 对突变不敏感
多项式插值 非线性变化的数据 拟合精度高 容易过拟合,外推风险大
KNN插值 多维特征相关 利用特征间关系 计算量大
# 线性插补示例
df['power'].interpolate(method='linear', inplace=True)

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

# 限制连续填充的最大数量(防止过度填充)
df['wind_speed'].fillna(method='ffill', limit=3, inplace=True)

避坑指南:我曾经在项目里用前向填充处理了连续2小时的缺失数据,结果模型预测偏差巨大。后来发现,那2小时正好是风速骤降时段,用前向填充完全掩盖了真实变化。记住:缺失超过一定阈值(比如连续10个点),就别插补了,直接标记为无效时段

4.3 数据归一化与标准化——让所有特征“站在同一起跑线”

风电数据里,风速可能是0-30m/s,功率是0-1500kW,温度是-20-40℃。这些量纲差异巨大。如果不做归一化,神经网络、SVM这类模型就会“偏心”——数值大的特征主导训练过程。

4.3.1 Min-Max归一化

把数据缩放到[0,1]区间。公式很简单:X_norm = (X - X_min) / (X_max - X_min)。适合数据分布比较均匀的情况。

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(df[['wind_speed', 'power']])

4.3.2 Z-score标准化

把数据变成均值为0、标准差为1的分布。公式:X_std = (X - μ) / σ。适合数据有异常值的情况,因为它不受极值影响。

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaled_data = scaler.fit_transform(df[['wind_speed', 'power']])

我的习惯:做预测时,我一般先用Z-score标准化。因为风电数据经常有极端天气事件,Min-Max会被这些极值“带偏”。但如果是做聚类或者可视化,Min-Max更直观。嗯,具体问题具体分析。

4.4 时间序列重采样——对齐时间“刻度”

风电数据采集频率五花八门。有的风场是1秒1个点,有的是10分钟1个点,还有的是15分钟。做预测前,必须统一时间分辨率。

重采样分两种:

  • 降采样:从高频到低频。比如把1秒数据聚合成10分钟数据。常用聚合函数:均值、中位数、最大值、最小值。
  • 升采样:从低频到高频。比如把10分钟数据插值到1分钟。这时候就要用到前面讲的插补方法了。
import pandas as pd

# 假设原始数据是1秒采样
df.index = pd.to_datetime(df['timestamp'])

# 降采样到10分钟,取均值
df_10min = df.resample('10T').mean()

# 降采样到1小时,取最大值(用于极端风况分析)
df_1h_max = df.resample('1H').max()

# 升采样:从10分钟到1分钟,线性插值
df_1min = df_10min.resample('1T').interpolate(method='linear')

注意:降采样时,千万别直接用均值。我见过有人把风速降采样取均值,结果把阵风特征全抹平了。对于风速,建议同时保留均值和最大值两个特征。对于功率,用均值更合理,因为功率是积分量。

好了,数据预处理这块就聊到这儿。这些技术看着基础,但真到了项目里,每一步都可能踩坑。记住一句话:数据预处理花的时间,永远值得

专注资料整理