4、风功率预测模型:基于机器学习的风功率预测(LSTM、XGBoost)、模型训练与评估、预测误差分析

风功率预测,说白了就是回答一个问题:明天风场能发多少电?

这个问题看似简单,但背后牵扯到气象、地形、机组状态、尾流效应……一堆变量。我刚开始做风电那会儿,用的还是物理模型加统计修正,准确率嘛,勉强能看。后来机器学习火起来了,我才发现——原来预测可以这么准

今天咱们就聊聊两种主流模型:LSTMXGBoost。它们各有各的脾气,用好了,发电量预测误差能压到 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 模型 超短期预测 (0~4h) XGBoost 模型 短期预测 (1~3天) 其他模型 物理模型 / 混合模型 模型评估 MAE / RMSE / MAPE / 误差分布 功率预测结果

这张图把整个流程串起来了:从原始数据开始,经过预处理,分流到 LSTM 或 XGBoost,最后评估输出。你可以在实际项目中,根据数据量和预测时长,选择走哪条路。


好了,这一章的内容就到这儿。模型选型、训练、评估、误差分析,每一步都有坑,但也都有解法。希望你能在自己的风场数据上试试,看看哪个模型更适合你。

最后说一句:模型只是工具,对风场的理解才是根本。多去现场看看风机怎么转的,比调参更有用。

专注资料整理