第二章:数据采集与预处理——SCADA系统与数据清洗实战
各位同学,大家好。今天我们来聊聊风功率预测里最基础、也最容易被忽视的一环——数据采集与预处理。
我见过太多团队,模型选得花里胡哨,结果数据一塌糊涂,预测精度根本提不上去。说白了,数据质量决定了模型的天花板。你想想看,垃圾数据进去,再牛的算法也白搭。
2.1 SCADA系统:风机的“黑匣子”
SCADA,全称是数据采集与监视控制系统。你可以把它想象成风机的“黑匣子”。它每时每刻都在记录风机的运行状态。
我个人习惯,拿到一个风场的数据,第一件事就是看SCADA的采样频率。大部分风场是10分钟一个点,也有1秒或1分钟的。频率不同,后续处理方式完全不同。
SCADA系统主要采集哪些数据?
- 气象数据:风速、风向、温度、气压、湿度
- 机组状态:有功功率、无功功率、桨距角、转速
- 运行参数:发电机温度、齿轮箱油温、振动值
我在项目中遇到过,有些风场的SCADA系统会漏记“风向”这个字段。当时我们做功率曲线分析,怎么拟合都不对。后来发现,风向数据缺失了整整三个月。嗯,这里要注意:缺失的字段,有时候比异常值更致命。
2.2 数据清洗:把“脏数据”洗干净
数据清洗,说白了就是“去伪存真”。SCADA数据里,什么妖魔鬼怪都有。
2.4.1 异常值处理
异常值分两种:一种是物理上不可能的值,比如风速500m/s;另一种是统计上离群的值,比如功率突然跳变。
我曾经处理过一个海上风场的数据,发现凌晨3点到5点,所有风机的功率都归零。一开始以为是停机维护,后来查日志才发现是SCADA通讯中断。这种“假停机”数据,如果不处理,模型会学到一个错误的规律:半夜没风。
我的处理原则:
- 物理阈值法:风速0~50m/s,功率0~额定功率×1.2
- 3σ原则:超出均值±3倍标准差的数据,标记为异常
- 四分位法:IQR(四分位距)之外的,视为离群点
代码示例(Python):
import pandas as pd
import numpy as np
# 物理阈值过滤
df = df[(df['wind_speed'] >= 0) & (df['wind_speed'] <= 50)]
df = df[(df['power'] >= 0) & (df['power'] <= rated_power * 1.2)]
# 3σ法
mean = df['power'].mean()
std = df['power'].std()
df = df[(df['power'] >= mean - 3*std) & (df['power'] <= mean + 3*std)]
2.4.2 缺失值处理
SCADA数据缺失,原因很多:传感器故障、通讯丢包、存储溢出。你想想看,一个10万条的数据集,缺失率超过5%,基本就不能直接用了。
我常用的方法有三种:
| 方法 | 适用场景 | 缺点 |
|---|---|---|
| 删除法 | 缺失率<1%,且随机缺失 | 浪费数据 |
| 插值法 | 短时间连续缺失(≤3个点) | 长序列插值会失真 |
| 模型预测法 | 缺失率较高(5%~20%) | 计算量大 |
避坑指南:我曾经用线性插值填补了连续2小时的缺失数据,结果模型预测的功率曲线出现了一个诡异的“平台”。后来才发现,插值把停机时段和运行时段连在了一起。所以,插值前一定要先判断机组状态。
2.3 数据标准化与归一化
为什么要做标准化?因为风速的单位是m/s,功率的单位是kW,温度的单位是℃。数值范围差好几个数量级。如果不处理,模型会天然认为“数值大的特征更重要”。
我个人习惯,对于树模型(随机森林、XGBoost),其实不太需要标准化。但对于神经网络、SVM、KNN这类模型,标准化是必须的。
2.3.1 归一化(Min-Max Scaling)
把数据压缩到[0,1]区间。公式很简单:
X_norm = (X - X_min) / (X_max - X_min)
代码示例:
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df[['wind_speed', 'power']] = scaler.fit_transform(df[['wind_speed', 'power']])
注意:归一化对异常值非常敏感。如果数据里有一个风速100m/s的异常点,归一化后正常数据会被压缩到很小的区间。所以,先清洗,再归一化。
2.3.2 标准化(Z-score Scaling)
把数据变成均值为0、标准差为1的分布。公式:
X_std = (X - μ) / σ
代码示例:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df[['wind_speed', 'power']] = scaler.fit_transform(df[['wind_speed', 'power']])
标准化不要求数据有上下界,适合有离群点的场景。我一般优先用标准化,除非模型明确要求归一化。
2.4 本章知识体系
下面这张图,是我自己总结的数据预处理流程。你把它打印出来贴在工位上,每次做数据都过一遍,能省不少事。
好了,这一章的内容就到这里。数据预处理是苦活、累活,但也是最有价值的活。你花80%的时间把数据搞干净,后面20%的时间建模就够了。
一句话总结:SCADA数据是金矿,但金矿里也有石头。清洗干净了,才能炼出金子。