第3章:数据采集与预处理模块
各位同学,今天我们来聊聊风电功率预测里最基础、也最容易被忽视的一环——数据采集与预处理。说实话,我见过太多项目,算法模型选得漂漂亮亮,结果一跑数据就崩了。为什么?因为数据质量不过关。你想想看,垃圾数据进去,再牛的模型也只能输出垃圾结果。
3.1 多源数据接入
风电功率预测,说白了就是靠数据吃饭。我们需要接入的数据源,主要有三类:
- SCADA数据:风机的运行状态数据,包括风速、转速、功率、桨距角等。采样频率通常是秒级或分钟级。
- NWP数据:数值天气预报数据,来自气象局或商业气象服务商。提供未来几天的风速、风向、温度、气压等预测值。
- 气象站数据:场站内实测的气象数据,比如测风塔的实时风速、风向。这玩意儿比NWP准,但覆盖范围有限。
我个人习惯,先把这三类数据的时间戳对齐。SCADA是本地时间,NWP通常是UTC时间,气象站可能又是另一种格式。嗯,这里要注意,时间同步是第一个坑。
核心要点:多源数据接入的关键是统一时间基准和采样频率。我建议所有数据都转为UTC时间,然后按15分钟或1小时重采样。
3.2 数据清洗与异常值处理
数据接入之后,你会发现什么妖魔鬼怪都有。风速负值、功率超过额定值、温度突然跳变几百度的……这些都得处理掉。
我常用的异常检测方法有几种:
- 阈值法:设定物理上下限。比如风速不可能超过50m/s,功率不可能超过额定值的1.2倍。
- 3σ原则:假设数据服从正态分布,超出均值±3倍标准差的数据视为异常。
- 箱线图法:用四分位数判断,超出1.5倍IQR范围的数据点。
- 变化率检测:相邻两个时间点的数据变化不能太离谱。比如风速1秒内从5m/s跳到30m/s,这明显是传感器故障。
避坑指南:我曾经遇到过一个项目,用3σ原则清洗数据,结果把正常的高风速段全删了。为什么?因为风速分布本身是偏态的,不是正态分布。后来我改用箱线法,效果就好多了。
处理异常值,我一般分两步走:先标记,再处理。标记出来的异常点,要么直接删除(如果比例很小),要么用前后正常值插补。
3.3 缺失值插补方法
数据缺失是家常便饭。传感器坏了、通信断了、维护停机……都会导致数据缺失。缺失比例超过30%的,我建议直接放弃这个数据段。
常用的插补方法,我按推荐顺序列一下:
| 方法 | 适用场景 | 我的评价 |
|---|---|---|
| 前向填充 | 短时间缺失(<5分钟) | 简单粗暴,但误差小 |
| 线性插值 | 中等时间缺失(5-30分钟) | 最常用,效果稳定 |
| 样条插值 | 长时间缺失(30分钟-2小时) | 曲线更平滑,但可能过拟合 |
| KNN插值 | 多变量相关场景 | 利用其他特征辅助,效果好但慢 |
| 模型预测插值 | 关键数据段 | 用历史数据训练模型预测缺失值 |
代码实现其实不复杂,我给大家看个简单的线性插值示例:
import pandas as pd
import numpy as np
# 假设df是包含风速和功率的DataFrame
# 时间索引已经对齐
# 线性插值
df['wind_speed_interp'] = df['wind_speed'].interpolate(method='linear')
# 如果缺失在开头或结尾,用前向/后向填充
df['wind_speed_interp'].fillna(method='ffill', inplace=True)
df['wind_speed_interp'].fillna(method='bfill', inplace=True)
# 检查插值效果
print(f"缺失值数量:{df['wind_speed'].isna().sum()}")
print(f"插值后缺失值:{df['wind_speed_interp'].isna().sum()}")
注意:插值不是万能的。如果缺失段内发生了剧烈的天气变化(比如阵风),线性插值会严重失真。这时候我建议结合NWP数据做辅助插值。
3.4 数据标准化与归一化
数据清洗完了,接下来就是标准化。为什么需要这步?因为不同特征的量纲差异太大了。风速是0-30m/s,功率是0-2000kW,温度是-20到40℃。如果不做处理,模型会天然偏向数值大的特征。
常用的方法有两种:
- Min-Max归一化:把数据缩放到[0,1]区间。公式是 (x - min) / (max - min)。适合数据分布比较均匀的情况。
- Z-score标准化:把数据变成均值为0、标准差为1的分布。公式是 (x - mean) / std。适合数据有异常值的情况。
我个人习惯,对于风电数据,风速和功率用Min-Max归一化,温度和气压用Z-score标准化。为什么?因为风速和功率的物理范围是固定的,而温度和气压的分布更接近正态。
from sklearn.preprocessing import MinMaxScaler, StandardScaler
# Min-Max归一化
scaler_minmax = MinMaxScaler()
df[['wind_speed', 'power']] = scaler_minmax.fit_transform(df[['wind_speed', 'power']])
# Z-score标准化
scaler_zscore = StandardScaler()
df[['temperature', 'pressure']] = scaler_zscore.fit_transform(df[['temperature', 'pressure']])
小技巧:标准化参数(min、max、mean、std)一定要保存下来。模型上线后,新数据要用同样的参数做变换,否则预测结果会偏移。我曾经吃过这个亏,上线后模型表现一塌糊涂,查了半天才发现是标准化参数没对齐。
3.5 整体流程梳理
说了这么多,我们来画个图,把整个数据预处理流程串起来。这样你心里就有个全局概念了。
你看,整个流程就是一条流水线。数据从左边进来,经过时间对齐、清洗、插补、标准化,最后变成干净、规整的数据集,可以直接喂给模型训练。
最后说一句,数据预处理没有银弹。每个风场的数据特点都不一样,你得先花时间了解数据,再决定用什么方法。我见过有人一上来就上复杂的插值模型,结果还不如简单的前向填充效果好。所以,先跑通,再优化,这是我一直坚持的原则。