☰
GMM+混合模型做多步风速预测:从状态聚类到模型融合的实战
2026/10/5 7:41:57 网站建设 项目流程

做多步风速预测这两年,我踩过的坑加起来能写一本小册子。风速这信号,上一秒温柔下一秒狂暴,靠单一模型想从头吃到尾,基本都会被真实数据教做人。后来我把混合模型的思想引进来,再用高斯混合模型(GMM)去拆解风速的不同状态,终于让预测结果从"能看"变成"能用"。这篇文章就聊聊我在这条路上怎么设计方案、怎么落地代码、又踩了哪些坑,适合正在做时间序列预测、风电功率预测,或者想认真搞明白混合模型的人参考。

1. 为什么单靠单一模型搞不定多步风速预测

1.1 多步风速预测到底难在哪

多步风速预测,通俗说就是给定过去一段时间观测值,要一次性预测未来N个时刻的风速。我一开始做的方案是"递归多步",也就是先用过去数据预测下一时刻,再把预测值当输入继续预测下下时刻,像一个滚雪球的过程。这样做的第一感觉是简单,但跑完测试集后会发现:误差随着步长成倍放大,到第8步以后基本和随机猜没太大区别。

问题就出在风速序列本身。风速不是平稳信号,它受地形、气压、温度、湍流影响,存在明显的日变化和天气过程变化。用一个全局模型去拟合所有状态,比如全用LSTM或者全用XGBoost,本质上是让同一个参数集合去描述各种天气背景下的风速规律。可实际情况是,晴天下午的阵风和台风过境前的持续大风,背后物理过程完全不同,模型很容易被平均掉,结果就是"既预测不准晴天,也预测不准台风"。

另外还有多步预测的策略选择问题。除了递归多步,还有直接多步(每个预测步建一个模型)和多输出多步(模型一次性输出多个时刻)。直接多步不累积误差,但是每个模型独立,会忽略步与步之间的相关性;多输出多步效率高,但输出维度大,模型容易学成平滑的均值,失去风速波动的尖峰。所以,光这一步就需要仔细权衡,这也是混合模型能发挥作用的地方。

1.2 混合模型的思路从哪来

混合模型的概念并不新鲜。很多聚类课程里,高斯混合模型(GMM)是和K-Means一起出现的,它本质上是一种软聚类方法,把样本看成来自若干个高斯分布,每个点以一定概率属于某个状态。放在风速预测里,这个思路刚好能解我的痛点:风速不是一个"单一模式""一个分布"就能描述完的,它更像是几种典型状态(比如大风过程、小风过程、过渡过程)混合出来的结果。

与其用一个全局模型硬拟合所有状态,不如先用GMM把历史样本按风速状态分群,然后在每个群上训练专门的预测模型。预测新样本时,先算它最可能属于哪个状态,再用对应的模型去预测。这样做的好处很直接:不同状态的规律被拆开了,模型不需要再"平均妥协"。

我最初也试过用K-Means分群,但很快就发现硬聚类的问题。风速状态之间没有清晰边界,比如"小风过程"和"过渡过程"中间区域,样本被强行划到一个类里,很容易产生边界噪声。而GMM输出的是每个簇的概率,这个概率不仅能帮我们选择模型,还能作为置信度参与最终的加权集成,对预测的稳定性帮助很大。这算是GMM在混合模型里的核心价值。

2. 混合模型方案设计:GMM怎么融进去

2.1 核心框架怎么定

我把整体框架分成三层:底层是GMM状态识别器,中层是多个子预测模型,顶层是输出决策模块。具体流程是:使用历史特征对训练样本做GMM聚类,得到K个状态簇和每个样本属于各簇的概率;接着在每个簇上分别训练自己的风速预测模型(我用过LSTM,也试过LightGBM);预测时,新样本先经过同一个GMM得到归属概率,然后每个子模型输出预测值,最后按概率加权求和,得到最终的多步风速预测结果。

为什么要这么设计?单纯把所有簇的模型输出做算术平均,其实退化成一种集成方法,效果有限。GMM概率其实携带了"当前的天气状态更像哪一种历史模式"的信息,把它作为权重去融合各簇模型的预测,相当于让模型在推理时做了隐式注意力。举个不太严谨但容易理解的例子:如果当前特征显示很大概率属于"强风过程",那强风子模型对最终预测的贡献就会更高,弱风子模型的影响被压低,这样预测结果就比全局模型更有针对性。

这个框架还可以换子模型。LSTM适合捕捉短期时序依赖,LightGBM对特征交互敏感,训练又快。我一个项目里用的组合是GMM+LSTM,另一个数据稀疏的项目换成了GMM+LightGBM。GMM部分保持稳定,子模型层可以根据数据量灵活更换。这算是混合模型比较舒服的扩展方式。

2.2 为什么选择GMM而不是K-Means

很多做预测的人一听"聚类分状态",第一反应就是K-Means,毕竟简单。但K-Means有两个问题在这个场景里很致命。第一,K-Means假设簇是球形的,风速特征不同维度之间的尺度差异会被粗暴对待;第二,它做的是硬划分,一个样本要么属于A簇要么属于B簇,但现实中处于两个天气过程交界处的样本并不罕见。

GMM则天然是软聚类。它假设数据由K个高斯分布混合而成,每个样本对每个高斯分量都有一个后验概率,这个概率是多值连续的。比如样本x属于强风状态的概率是0.7,属于过渡状态的概率是0.3,那最终预测可以按0.7和0.3加权融合两条路线,而不是非此即彼。

实际训练中,我用GMM的GaussianMixture的时候通常还会做两件事:用BIC或AIC来决定K值,以及比较不同的协方差类型(full、diag、tied、spherical)。风速特征里面往往存在相关性,比如风速和阵风、风向分量之间会有关联,无脑用spherical协方差等于浪费了特征关系,但full协方差在小样本上容易过拟合。我一般从diag起步,如果数据量足够再试full,用BIC选稳妥的。这个细节决定了GMM能不能有效捕捉风速的多种状态。

2.3 多步预测解码策略的选择

框架定了,还有一个重要部件:多步预测究竟怎么解码。我上面提到三种策略,但它们对偏差的累积程度不一样。递归多步最省资源,但对混合模型来说有个致命伤:一旦某一步预测偏差大,后续状态归属判断也会跟着歪,子模型选错,误差雪球越滚越大。直接多步每个模型独立,不累积误差,但如果每个步长都要建一个子模型,K个簇乘以H个步长,模型数量会爆炸,训练和维护成本很高。

所以我在生产方案里通常用"直接多步与迷你递归结合"的折中:先用GMM归属概率选择子模型,子模型一次输出中期窗口中的几个关键节点(比如未来第1步、第3步、第6步),中间步长用递归插值补齐。这样既控制了模型数量,又避免了每步都递归带来的误差雪崩。这个设计不是唯一答案,但对我遇到的数据集来说,综合效果最好,稳定性和训练成本都比较可控。

3. 实操闭环:从特征工程到模型训练

3.1 数据准备和滑窗构造

数据我用的是某风场10分钟间隔的测风塔数据,连续约8个月。特征先做基础清理:去掉停机时段、极端毛刺,再对缺失的小段进行线性插值。原始列包括风速、风向、温度、气压,以及由风速转换出的东西向u分量和南北向v分量。风向单独拿来做聚类没有太大意义,因为360度环绕的特性会让归一化出问题,所以我会把风向转成sin/cos两列。

滑窗构造上,输入过去12个时刻(即2小时)的序列,预测未来24个时刻(即4小时)的24步风速。这里有个容易忽略的细节:训练集和验证集必须按时间顺序切分,不能随机打乱。风速序列有强自相关性,随机切分会把未来的信息泄漏到训练里,验证集表现会虚高,导致部署后翻车。

我常用的特征组合是:过去两个月的历史风速均值,用于反映季节背景;过去12步风速的滑动均值、滑动方差,用于刻画当前状态的稳定性;风速变化率序列,用于捕捉加速/减速过程;还有时间特征(一天内的小时正弦编码)。这些特征会同时进入GMM聚类和子模型,但GMM用到的特征会稍微精简一些,避免维度太高把聚类结果带偏。

3.2 GMM聚类的具体操作和代码

GMM部分我没有用特别复杂的手段,主要靠pipeline和BIC选择。先对聚类特征做标准化,然后从K=2到K=8搜索,每个K用10个随机种子跑一遍,记录BIC得分。代码可以这样写:

from sklearn.mixture import GaussianMixture from sklearn.preprocessing import StandardScaler import numpy as np # cluster_feat 是用于聚类的特征矩阵(例如风速、滑动均值、d(u)/dt等) scaler = StandardScaler() X_scaled = scaler.fit_transform(cluster_feat) best_k = None best_bic = np.inf best_gmm = None for k in range(2, 9): models = [] bics = [] for seed in range(10): gmm = GaussianMixture( n_components=k, covariance_type="diag", random_state=seed, max_iter=200, n_init=5, ) gmm.fit(X_scaled) models.append(gmm) bics.append(gmm.bic(X_scaled)) # 取10次训练BIC的中位数,降低随机性影响 idx = np.argsort(bics)[len(bics) // 2] if bics[idx] < best_bic: best_bic = bics[idx] best_k = k best_gmm = models[idx] proba = best_gmm.predict_proba(X_scaled) label = proba.argmax(axis=1)

有几点经验值得说。第一,GMM不是训练次数越多越好,n_init=5加多个随机种子足够稳定,因为风速特征相对温和,不会出现特别病态的分布。第二,不要直接拿原始风速做聚类而不做标准化。风速数值范围太大,很容易让GMM把高低风速当成两个簇,但真正的状态差异可能在相对变化上。第三,BIC和业务可解释性要结合看,有时候BIC选出的K值虽然最优,但某个簇的实际含义很模糊,我会适当减小K,方便后续分析。

3.3 子模型训练:LSTM和LightGBM两条路线

子模型我实际试过两种,先说LSTM。每个簇单独训练一个LSTM,输入形状是(batch, 12, feature_dim),输出是预测步长数。我用的结构是单层LSTM(64个单元)加一个全连接输出层,损失用MAE,优化器Adam,学习率1e-3,早停轮数10。单独每个簇样本量不大,结构太复杂容易过拟合,单层就够了。训练时需要注意,簇标签是用整个训练集的特征做的,但子模型只接收对应簇的样本,所以训练样本量其实被切小了,如果某个簇样本太少,可以考虑把该簇直接用全局模型兜底。

LightGBM路线则更简单。对每个簇,把过去12步的序列特征展开成扁平向量,目标值直接是未来24步的向量,回归每个步长用LGBMRegressor。这样每个簇其实是24个模型,但LightGBM训练很快,完全可以接受。加上LightGBM对特征交互很友好,像风向正弦和风速变化率这种组合特征它能自己学出规律,不需要我手工构建太多交叉项。

预测时,新样本x先过GMM得到概率p_k,每个簇模型输出pred_k,最终预测是np.sum([p_k * pred_k for k in range(K)], axis=0)。从代码角度看就这几行,但这是整个混合模型最核心的输出逻辑。

3.4 超参数和损失函数怎么选

损失函数方面,我最终选了Huber损失而不是MAE或MSE。MAE在极端风速下不够敏感,MSE又太看重少数尖峰。Huber在误差较小时接近MSE、误差大时接近MAE,非常适配风速这种带尖峰的时间序列。具体delta设为1.0,训练时对每个输出步长等权处理。

LSTM的学习率、批次大小、隐藏层大小可以用简单的手工搜索。我建议先固定其他参数只调学习率,找到曲线能稳定下降的范围,再微调隐藏单元数。LightGBM这边反而更好办,用早停+较浅的树深度(比如6-8),配合较大的学习率0.05,训练快也不容易过拟合。每次调完之后一定要在独立测试集上验证,不能只看训练集误差。

4. 评估调优与常见问题排查

4.1 评估指标怎么设计

多步预测不能只看一个总误差。我把未来24步分成三组:短期(1-6步,约1小时)、中期(7-12步)、长期(13-24步),分别计算MAE和RMSE。这样能清楚看出混合模型在哪个预测区间优势最大。我实测下来,短期步长混合模型的提升并没有想象中明显,因为没有足够时间让状态差距显现;但从第8步开始,GMM分状态加权的优势会逐步拉开,长期步长的误差比单一LSTM能低10%-15%,这个提升对风电调度来说已经很值得投入了。

除了误差,还有一个常被忽略的指标是"方向命中率"——预测风速是上升还是下降与实际是否一致。混合模型因为有分状态结构,在风速趋势转折点附近表现更稳,方向命中率比单一模型高了不少。我在实际业务中反而更看重这个指标,因为调度决策往往依赖的是趋势和变化幅度,而不是绝对值的毫厘之差。

4.2 训练过程中最常踩的坑

第一个坑是GMM聚类状态不稳定。同样一套特征,随机种子换一下,某个簇的样本归属就变了,子模型跟着重建,最终预测波动很大。这个问题的解法我前面提到过,就是用多个随机种子训练取最稳定的结果(比如按BIC中位数),或者在线上用最近一个周期滚动训练,让簇结构保持相对稳定。

第二个坑是模型在预测长期风速时会趋向于"平均化"。比如明明风速正在快速爬升,预测曲线却慢慢变成一个平缓的均值,尤其在递归多步策略下非常明显。这是因为子模型学到的输出分布里,平均值最安全,损失最小。我碰到这个问题后引入了两个修正:一是输入中添加"当前风速的加速度",强化趋势信息;二是使用非对称损失,对低估风速上升的样本给更高惩罚,让模型不那么容易偷懒。

第三个坑是极端天气下GMM的失效。比如测试集里出现了一个台风过程,历史训练中这种样本很少,GMM可能只给一个很低的概率归属,所有子模型都没有针对这种状态的专门训练,最终预测就会稀里糊涂。这个问题很难彻底解决,我的应对是设置一个概率阈值:如果GMM在任何簇上的归属概率都低于阈值(比如0.4),就不强制融合,直接退回全局模型并加一个较大的误差区间,宁可预测保守一点,也不给调度一个"看似准确其实离谱"的数值。

4.3 特征重要性分析带来的意外发现

用LightGBM子模型时,我可以直接拿到特征重要性评分。做完几组实验后发现一个有意思的事:对24步长期预测贡献最大的特征并不是风速历史值,而是风速的滑动方差和风向sin/cos组合。滑动方差反映了湍流强度,湍流强的时刻风速波动剧烈,预测难度高;而风向突变往往意味着天气系统转换,是状态切换的前兆。这个发现反过来让我去优化GMM的输入特征,把滑动方差这一项权重提高,聚类结果从4簇变成了更清晰的5簇,长期误差又降了一点。

这也说明混合模型的收益不只是靠模型堆叠,更关键的是让聚类部分和特征工程对齐。GMM分出来的簇不应该只是统计上可分,更应该在物理含义上有区分度,比如一个是"平稳小风"、一个是"强风过程"、一个是"风向转换过渡期"。如果能做到这一步,子模型学到的规律就更容易被理解,调试起来也更有方向感。

5. 问题排查速查表和心得收尾

我把实际项目中遇到的高频问题整理成了表格,方便大家排查:

现象可能原因解决方法
GMM聚类结果每次跑都不一样初始值随机、样本分布重叠多随机种子训练取BIC中位数;固定random_state
预测长期步长全部拉平为均值递归误差累积;子模型输出趋于平均改直接多步;加趋势特征;用Huber损失
聚类簇数量和物理状态对不上聚类特征里混入了太多无关维度精简GMM特征,突出风速变化率和湍流指标
极端天气下预测异常离谱GMM无法识别低频状态设置概率阈值,退回全局模型并放大置信区间
子模型训练集过小导致过拟合GMM把样本分得太细减少K值;用LightGBM代替LSTM;或对少数簇共用全局模型
验证集表现好、线上效果差训练/测试数据没有严格按时间切分重新用时间序列split,禁止随机打乱

最后再分享一个小经验。混合模型不是万能的,它的核心价值在于让模型去"分工",而不是单纯堆数量。我在实际使用中印象最深的一点是,GMM输出的归属概率本身就是一个很有用的置信度量。预测时它告诉我"当前样本和强风过程的匹配度只有0.3,和过渡状态匹配度是0.6",那我输出的风速曲线就应当偏保守,而不是假装很确定。这个隐含的不确定性信息,比单纯提高准确率更值钱,尤其在给风电场做调度决策的时候,它直接决定了你愿不愿意相信这条曲线。如果你正在做类似的预测问题,建议先把状态识别和特征对齐做好,再谈复杂模型,这条路会顺很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询