4、风功率预测模型:基于机器学习的风功率预测(LSTM、XGBoost)、模型训练与评估、预测误差分析
风功率预测,说白了就是回答一个问题:明天风场能发多少电?
这个问题看似简单,但背后牵扯到气象、地形、机组状态、尾流效应……一堆变量。我刚开始做风电那会儿,用的还是物理模型加统计修正,准确率嘛,勉强能看。后来机器学习火起来了,我才发现——原来预测可以这么准。
今天咱们就聊聊两种主流模型:LSTM 和 XGBoost。它们各有各的脾气,用好了,发电量预测误差能压到 5% 以内。
4.1 为什么选 LSTM 和 XGBoost?
你可能会问:深度学习模型那么多,为啥偏偏提这两个?
我个人习惯是这样分的:
- LSTM:擅长处理时间序列。风速、风向、温度这些数据,天然就是按时间排列的。LSTM 能记住过去几小时甚至几天的变化规律,适合做超短期预测(未来 0~4 小时)。
- XGBoost:擅长处理特征交互。比如风速、湍流强度、空气密度、桨距角……这些特征之间怎么组合影响功率?XGBoost 能自动帮你找到最佳分裂点,适合做短期预测(未来 1~3 天)。
我在项目中遇到过这样的情况:用 LSTM 做 15 分钟前的预测,误差不到 3%;但拉到 24 小时,误差就飙到 15% 以上。这时候换成 XGBoost,反而更稳。所以,没有万能模型,只有合适场景。
核心思路:超短期用 LSTM,短期用 XGBoost,两者互补。
4.2 LSTM 模型:让网络学会“记住”风的变化
LSTM 的全称是长短期记忆网络。名字挺长,但核心就一句话:它能记住哪些信息该保留,哪些该遗忘。
举个例子:风速从 5m/s 突然升到 12m/s,功率会怎么变?LSTM 会记住过去 1 小时的风速变化趋势,结合当前值,给出一个合理的功率输出。而不是像普通神经网络那样,只看当前时刻的数据。
4.2.1 数据准备
嗯,这里要注意:LSTM 对数据格式有要求。输入必须是 [样本数, 时间步长, 特征数] 的三维张量。
我一般这样处理:
import numpy as np
from sklearn.preprocessing import MinMaxScaler
# 假设 data 是原始风速、风向、温度、功率数据
scaler = MinMaxScaler()
data_scaled = scaler.fit_transform(data)
# 构造时间序列样本
def create_sequences(data, seq_length=24):
X, y = [], []
for i in range(len(data) - seq_length):
X.append(data[i:i+seq_length, :-1]) # 前 seq_length 步的特征
y.append(data[i+seq_length, -1]) # 当前时刻的功率
return np.array(X), np.array(y)
seq_length = 24 # 用过去 24 个时间点预测下一个
X, y = create_sequences(data_scaled, seq_length)
print(X.shape) # 输出: (样本数, 24, 特征数)
这里 seq_length 选 24,是因为我习惯用过去 2 小时(每 5 分钟一个点)的数据来预测未来 5 分钟。你想想看,如果只给模型看过去 1 个点,它根本抓不住趋势。
4.2.2 模型搭建
LSTM 的层数不宜太多。我踩过坑:一开始堆了 3 层 LSTM,训练慢不说,还过拟合。后来发现,2 层 LSTM + 1 层 Dropout 就够用了。
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
model = Sequential([
LSTM(64, return_sequences=True, input_shape=(X.shape[1], X.shape[2])),
Dropout(0.2),
LSTM(32, return_sequences=False),
Dropout(0.2),
Dense(16, activation='relu'),
Dense(1) # 输出功率
])
model.compile(optimizer='adam', loss='mse')
model.summary()
这里 return_sequences=True 是为了让第一层 LSTM 输出完整的时间序列给第二层。最后一层用线性激活,因为功率预测是回归问题。
小技巧:训练时加上 EarlyStopping,当验证集损失连续 10 轮不下降就停止。我曾经有一次没加,模型跑了 200 轮,结果验证集误差反而上升了。
4.3 XGBoost 模型:用树模型做回归
XGBoost 是梯度提升树的一种实现。它的优势在于:对特征工程要求低,自带正则化,不容易过拟合。
我个人的经验是:如果特征数量不多(比如 10~20 个),XGBoost 的效果往往比深度学习还好。尤其是当数据量不大时(比如只有几千条),XGBoost 的泛化能力更强。
4.3.1 特征构造
XGBoost 不需要时间步长,但需要你手动构造一些特征。我常用的特征包括:
- 当前风速、风向(正弦/余弦编码)
- 过去 1 小时平均风速、最大风速
- 空气密度(由温度和气压计算)
- 湍流强度(风速标准差/平均风速)
- 时间特征:小时、月份、季节
举个例子:
import pandas as pd
import numpy as np
# 假设 df 包含原始数据
df['wind_sin'] = np.sin(np.deg2rad(df['wind_dir']))
df['wind_cos'] = np.cos(np.deg2rad(df['wind_dir']))
df['turbulence'] = df['wind_speed'].rolling(12).std() / df['wind_speed'].rolling(12).mean()
df['air_density'] = df['pressure'] / (287.058 * (df['temperature'] + 273.15))
# 滞后特征:过去 1 小时的平均风速
df['wind_avg_1h'] = df['wind_speed'].rolling(12).mean()
features = ['wind_speed', 'wind_sin', 'wind_cos', 'turbulence',
'air_density', 'wind_avg_1h', 'hour', 'month']
X = df[features].dropna()
y = df['power'].loc[X.index]
这里风向用正弦余弦编码,是因为 0° 和 360° 其实是一个方向,直接输入数值会让模型误以为差距很大。
4.3.2 模型训练
import xgboost as xgb
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = xgb.XGBRegressor(
n_estimators=500,
max_depth=6,
learning_rate=0.05,
subsample=0.8,
colsample_bytree=0.8,
reg_alpha=0.1,
reg_lambda=1.0,
random_state=42
)
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)
参数 max_depth=6 是我试出来的。太深容易过拟合,太浅欠拟合。6 层对于风功率预测来说,刚刚好。
注意:XGBoost 对缺失值敏感。如果某个传感器坏了,数据出现 NaN,一定要先填充或删除。我曾经因为一个风速传感器故障,导致模型预测值全部偏大 20%。排查了两天才发现是数据问题。
4.4 模型评估:不只是看 R²
很多人习惯用 R² 来评估回归模型。但风功率预测不一样——我们更关心误差的绝对值。
我常用的指标有三个:
| 指标 | 公式 | 说明 |
|---|---|---|
| MAE | \(\frac{1}{n}\sum |y_i - \hat{y}_i|\) | 平均绝对误差,单位 kW |
| RMSE | \(\sqrt{\frac{1}{n}\sum (y_i - \hat{y}_i)^2}\) | 均方根误差,对大误差更敏感 |
| MAPE | \(\frac{100\%}{n}\sum \frac{|y_i - \hat{y}_i|}{y_i}\) | 平均绝对百分比误差,单位 % |
举个例子:如果风场额定功率是 50MW,MAE 是 2MW,那误差率就是 4%。这个数字,电网调度那边是可以接受的。
我一般会画一个预测 vs 实际的散点图:
import matplotlib.pyplot as plt
y_pred = model.predict(X_test)
plt.scatter(y_test, y_pred, alpha=0.5)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--')
plt.xlabel('实际功率 (kW)')
plt.ylabel('预测功率 (kW)')
plt.title('预测 vs 实际')
plt.show()
如果散点都集中在红线附近,说明模型不错。如果出现明显的弯曲或离散,那就得回头检查特征或模型了。
4.5 预测误差分析:找到“坏点”
模型建好了,误差也算了,然后呢?
我习惯做一步:误差分布分析。说白了,就是看看哪些情况下模型容易出错。
常见的误差来源有:
- 风速突变:比如阵风从 8m/s 跳到 15m/s,模型反应不过来。这时候 LSTM 比 XGBoost 表现好一点,因为 LSTM 能记住趋势。
- 低风速段:风速低于 3m/s 时,机组可能停机,功率为 0。但模型可能会预测出一个小正值。我一般会加一个阈值判断:如果风速低于切入风速,直接输出 0。
- 限功率运行:电网调度要求限功率时,实际功率会低于理论值。模型如果没学到这个特征,就会高估。解决方案是加入“限功率标志”作为特征。
我曾经遇到过一个案例:某个风场在冬季误差特别大。后来发现,是因为叶片结冰导致功率下降,但模型没有考虑温度对叶片气动性能的影响。后来我加入了“结冰指数”特征,误差立刻降下来了。
避坑指南:不要只看整体误差。按风速段、季节、时间段分别分析误差,才能找到模型的真正短板。
4.6 知识体系总览
下面这张图,是我自己总结的风功率预测模型核心逻辑。你可以把它当作一个快速参考:
这张图把整个流程串起来了:从原始数据开始,经过预处理,分流到 LSTM 或 XGBoost,最后评估输出。你可以在实际项目中,根据数据量和预测时长,选择走哪条路。
好了,这一章的内容就到这儿。模型选型、训练、评估、误差分析,每一步都有坑,但也都有解法。希望你能在自己的风场数据上试试,看看哪个模型更适合你。
最后说一句:模型只是工具,对风场的理解才是根本。多去现场看看风机怎么转的,比调参更有用。