做回归预测的人应该都有过这种体验:模型选型其实不是最难的,难的是让一个看起来还不错的模型真正发挥出应有的水平。就拿极限学习机(ELM)来说,训练速度快得离谱,泛化能力也不差,但它的隐层节点数和随机映射不确定性让人头疼;换上核极限学习机(KELM)之后,随机性消失了,又多出两个需要手工敲定的超参数——正则化系数和核参数。这两个参数定不好,哪怕同一个数据集,预测精度也能差出一大截。
这篇文章就围绕一个非常具体、也很有代表性的组合来聊:用鲸鱼优化算法(WOA)去优化核极限学习机(KELM)的超参数,搭出一个回归预测模型。我会从为什么选这个组合讲起,把WOA的搜索逻辑、KELM的数学结构、两者的衔接方式、核心代码怎么写、效果怎么评估、实践中有哪些坑,全部按我自己的实现过程梳理一遍。适合正在做回归预测,又想把手里的模型调得再准一点的工程师和学生参考。
1. 为什么是WOA优化KELM,而不是别的组合
1.1 KELM的痛点:快是真的快,参数也是真的难定
先聊KELM本身。极限学习机(ELM)的核心思路,是用一个随机映射把输入数据丢到高维空间,然后用最小二乘一步算出输出权重,完全绕开了反向传播。好处是训练速度极快,坏处是“随机”这两个字让人不放心:换个随机种子,结果就抖一抖,隐层节点数还得自己试。
核极限学习机就是在ELM的框架上,用核函数替代原本的随机隐层映射,把随机性彻底消掉:不用再指定隐层节点数,只需要定义一个核函数,比如RBF核。但代价随之而来——模型从“调隐层节点数”变成了“调两个超参数”。RBF核的宽度参数决定每个样本的影响半径,正则化系数C决定模型对训练误差的容忍度。两者一组合,就是一个二维的搜索空间,而且它们对预测精度的影响是非线性的,甚至相互耦连。C取太大容易把噪声也学进去,取太小模型又学不到位;核参数取太大,每个点都只顾自己,取太小,所有点都糊成一团。
项目里如果只用默认参数,经常出现一种尴尬情况:看着别人论文里KELM能跑到0.95以上的R²,自己跑出来只有0.7多。问题多半就出在超参数上,而不是模型结构本身。
1.2 传统调参手段为什么不够用
KELM的超参数虽然只有两个,但真要手动调,麻烦程度一点不少。
网格搜索是最直接的办法,思路是把C和核参数各取几十个候选值,排列组合全跑一遍。听起来简单,算起来很痛。假设C取20个候选、核参数取20个候选,就是400组参数;如果每组参数再用5折交叉验证评估,那就得训练2000次。KELM单次训练虽然快,可一旦数据量上千条,核矩阵是N×N计算的,累计下来的时间就很可观。这还只是二维参数空间,后面如果想把特征选择、其他核函数一起加进来,网格搜索直接维度灾难。
随机搜索比网格搜索聪明一些,能在更少的尝试里找到还不错的点,但它本质上是碰运气,不会利用已经评估过的参数信息去指导下一步搜索。手动试错就更不用说了,不可复现,也说不清楚为什么这样调。
所以,把超参数寻优交给群智能优化算法,是一个很自然的选择。
1.3 为什么是WOA:三个理由
群智能优化算法里,粒子群(PSO)、遗传算法(GA)都很常见,但我最后选了鲸鱼优化算法(WOA),主要看中三点。
第一是参数少。WOA的核心机制模拟座头鲸的泡泡网捕食行为,分成收缩包围、螺旋更新位置、随机搜索三个阶段,真正要设置的算法参数极少,本质上只有种群大小和迭代次数。相比之下,GA要调交叉概率、变异概率、选择策略,PSO要调惯性权重、个体学习因子、社会学习因子,每个参数调起来都是额外一堆工作量。
第二是全局搜索和局部开发的平衡做得好。WOA通过一个系数A的控制,在前期倾向于全局探索,后期倾向于局部精细搜索,天然适合处理超参数空间中那种“不知道最优值在哪个区域”的情况。KELM的超参数最优值在不同数据集上差异很大,有的最优C在0.1附近,有的在100以上,这种不确定性正好需要前期较强的全局扫描能力。
第三是实现简单。WOA的核心循环代码量很小,我后面会贴完整实现,即便第一次接触,照着写半小时也能跑通。对工程场景来说,“好调试”本身就是巨大优势。
当然,这不代表WOA在所有问题上都比PSO和GA强。实际问题里,算法效果和数据特征关系很大,我一般会同时跑一个PSO做对照,后面实验部分也会放对比结果。
1.4 不要忽略XGBoost:为什么必须拉它做对比
聊KELM的时候,很多人会问一个问题:既然XGBoost这类梯度提升树在表格数据上这么强,为什么还要费劲去优化KELM?
这个问题问得对。现代回归预测场景里,XGBoost、LightGBM几乎成了默认标杆,它们在特征交互、非线性拟合、缺失值处理上都有成熟的优势。我这次把XGBoost专门拉出来做对照,不是为了证明谁比谁强,而是为了回答一个更现实的问题:KELM经过超参数优化之后,和主流树模型相比还有多大竞争力,以及在什么场景下值得选它。
答案其实很清晰:KELM家族的优势不在精度上限,而在推理效率和某些特定场景的适配性。训练完成后,KELM的预测就是核函数计算加一次内积,没有树的逐层分裂判断,更利于并行化和硬件部署。在中小样本、高维非线性回归、在线学习这类场景里,KELM依然有它的位置。这篇文章后面会用同一组数据给出WOA-KELM和XGBoost的量化对比,让数字说话。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. WOA到底在优化什么:数学逻辑与工程映射
2.1 KELM的数学结构先搞清楚
要把WOA用明白,至少得知道KELM在算什么东西。
标准ELM假设有一个随机映射h(x)把输入映射到隐层特征空间,输出权重β通过最小二乘求解。核极限学习机的做法,是用一个核矩阵替换掉ELM中的随机映射矩阵。给定N个训练样本,核矩阵Ω的第(i,j)个元素就是K(x_i, x_j),其中K是核函数。RBF核的表达式是:
K(x_i, x_j) = exp(-γ * ||x_i - x_j||²)
注意这里的γ,在不同的库和文献里可能叫gamma,也可能叫1/(2σ²)。它本质上控制了样本之间相似度随距离衰减的速度。
KELM的输出权重求解公式为:
α = (Ω + I/C)^(-1) * Y
其中C是正则化系数,I是单位矩阵,Y是训练标签向量。对新样本x做预测时,先计算它和所有训练样本的核函数值向量K(x),然后输出:
f(x) = K(x) * α
这个形式和核岭回归(Kernel Ridge Regression)几乎完全一致。所以在代码实现里,可以直接用KernelRidge来充当KELM的回归核心,只需要把alpha参数设置成1/C就行了。这一点很重要,后文代码会用到。
2.2 把超参数编码成鲸鱼的位置向量
WOA里每个个体(鲸鱼)代表一个候选解。在KELM的调参问题里,一个解就是一组(C, γ)。所以鲸鱼的位置向量是二维的:
X = [C, γ]
初始化时,在设定的搜索范围内随机生成很多个这样的二维向量。每个向量代入KELM训练,算出预测误差,误差越小说明这组参数越好。WOA的迭代过程就是不断移动这些二维向量,往误差更小的区域靠拢。
这里有一个非常关键的工程细节:C和γ的取值范围通常跨越多个数量级。比如C常见范围是[0.001, 1000],γ常见范围是[0.0001, 10]。如果直接在这个线性空间里随机初始化,绝大多数点会集中在数值较大的区域,而真正的最优值可能藏在很小的数值范围内,算法很难找到。
解决办法是把搜索空间从线性空间转到对数空间。具体来说,WOA搜索的变量是log10(C)和log10(γ),每次评估适应度时再换回真实的C和γ。这样0.001和1000在对数尺度上均匀分布,搜索效率高很多。这个细节很多人会忽略,但实际效果差别巨大。
2.3 适应度函数:为什么必须用交叉验证误差
有了候选解,怎么评判好坏?最直接的想法是用KELM在训练集上的误差。但这里有个陷阱:直接用训练误差做适应度,选出来的参数一定是过拟合的,因为C和γ的组合可以让模型在训练集上无限逼近,但对新数据毫无意义。
我自己常用的方案是K折交叉验证的均方根误差(RMSE)。把训练集切成K份,每次用K-1份训练、1份验证,轮流做K次,最后把验证误差平均起来作为适应度。这样选出的参数代表的是“泛化能力更好”的参数,而不是“记住训练集”的参数。
样本量不大的时候,K取5比较稳妥;样本量只有几百条,可以取3;样本量很大,比如好几万条,做5折交叉验证的计算成本就很高,可以退一步用留出验证集。WOA-KELM这个组合里,适应度函数会被调用非常多次,所以折数的选择要兼顾稳健性和计算开销。
2.4 WOA的三个搜索动作:收缩包围、螺旋更新、随机搜索
简单讲一下WOA每次迭代在做什么。每轮迭代中,算法先找到当前种群中最优的个体X*(t),其他个体向它靠拢。靠拢方式有三种:
第一种是收缩包围。位置更新公式为X(t+1) = X*(t) - A * D,其中D是当前个体与最优个体之间的距离,A是一个随迭代从2线性降到0的系数。A的绝对值小于1时,个体被拉向最优解,相当于局部开发。
第二种是螺旋更新。个体以螺旋轨迹逼近最优解,公式里带一个cos项。这种机制让个体在靠近最优解的同时还能绕着它转圈,避免所有个体一下子挤到同一个点上。
第三种是随机搜索。当A的绝对值大于等于1时,个体不再向当前最优解靠拢,而是随机选一个其他个体作为参照去探索未知区域。这个机制保证了前期算法不会过早收敛到局部最优。
三种动作的切换由一个随机概率p控制。整体看下来,WOA的思路就是:前期多随机探索,后期多局部开发,中间用螺旋保持多样性。这个节奏对KELM这种“最优参数区域不明确”的优化问题很合适。
3. 从零手写WOA-KELM回归模型:核心代码拆解
3.1 环境准备与数据加载
我用Python实现,依赖库最好控制在最少,方便你直接复现。除了常规的numpy、pandas、sklearn,不需要额外安装深度学习框架。
这里以UCI的混凝土抗压强度数据集为例,1030条样本,9个特征,预测目标就是混凝土28天抗压强度(MPa)。这类数据集会有明显的非线性关系,适合用来验证优化算法的价值。
python复制import numpy as np
import pandas as pd
from sklearn.kernel_ridge import KernelRidge
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error
# 假设你已经把数据集下载为concrete.csv
df = pd.read_csv("concrete.csv")
X = df.iloc[:, :-1].values
y = df.iloc[:, -1].values
# 切分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 标准化:注意先fit训练集,再transform测试集
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
数据标准化这一步不能省。RBF核函数内部计算的是样本之间的欧氏距离,如果特征量纲差异大,距离就被量纲大的特征主导了,核函数的作用会被严重扭曲。
3.2 用KernelRidge实现KELM评估核心
前面说过,KELM回归和核岭回归数学上等价。所以评估一组(C, γ)的适应度,可以直接用KernelRidge。
python复制def kelm_cv_score(params, X, y, cv=5, seed=42):
# params = [C, gamma]
C = params[0]
gamma = params[1]
model = KernelRidge(kernel="rbf", alpha=1.0/C, gamma=gamma)
scores = cross_val_score(
model, X, y, cv=cv,
scoring="neg_mean_squared_error",
n_jobs=-1
)
# cross_val_score返回负MSE,取平均再取负得到正MSE
mse = -scores.mean()
return mse
这里把C映射成alpha=1/C,含义是C越大,正则化越弱。gamma直接传给KernelRidge。返回的是MSE,后面WOA里要做最小化。
有一个容易写错的地方:交叉验证里如果不固定random_state,每次评估同一组参数得到的适应度会不一样,因为数据划分的随机性会导致MSE抖动。这在启发式优化里很致命,适应度曲线会反复震荡,算法很难判断到底哪个解更好。所以我在cross_val_score里固定了随机种子。如果cv用的都是默认的KFold,可以给KFold传入shuffle=True和random_state=42,效果也一样。
3.3 WOA优化器主循环
接下来是WOA的核心实现。我写的版本保持了经典WOA的结构,同时加了边界裁剪和贪婪保留策略。所谓贪婪保留,就是新位置如果比旧位置好才替换,否则保留旧位置。这样可以保证种群整体质量只增不减。
python复制def woa_optimize(X, y, n_pop=20, max_iter=30, lb=None, ub=None):
ndim = len(lb)
# 初始化鲸鱼种群位置
whales = np.random.uniform(lb, ub, size=(n_pop, ndim))
fitness = np.array([kelm_cv_score(10**w, X, y) for w in whales])
# 10**w 是因为我们在log空间搜索
best_idx = np.argmin(fitness)
leader_pos = whales[best_idx].copy()
leader_score = fitness[best_idx]
for t in range(max_iter):
# a 从 2 线性下降到 0
a = 2 - 2 * t / max_iter
for i in range(n_pop):
r1 = np.random.rand()
r2 = np.random.rand()
A = 2 * a * r1 - a
C_coef = 2 * r2
p = np.random.rand()
b = 1
l = np.random.uniform(-1, 1)
if p < 0.5:
if abs(A) < 1:
# 收缩包围
D = np.abs(C_coef * leader_pos - whales[i])
new_pos = leader_pos - A * D
else:
# 随机搜索猎物
rand_idx = np.random.randint(n_pop)
rand_whale = whales[rand_idx]
D = np.abs(C_coef * rand_whale - whales[i])
new_pos = rand_whale - A * D
else:
# 螺旋更新位置
Dp = np.abs(leader_pos - whales[i])
new_pos = Dp * np.exp(b * l) * np.cos(2 * np.pi * l) + leader_pos
# 边界裁剪
new_pos = np.clip(new_pos, lb, ub)
# 贪婪保留:新解更优才更新
new_fitness = kelm_cv_score(10**new_pos, X, y)
if new_fitness < fitness[i]:
whales[i] = new_pos
fitness[i] = new_fitness
# 更新全局最优
best_idx = np.argmin(fitness)
if fitness[best_idx] < leader_score:
leader_score = fitness[best_idx]
leader_pos = whales[best_idx].copy()
print(f"iter {t+1:02d}, best RMSE: {np.sqrt(leader_score):.4f}")
# 返回真实空间中的最优参数
best_C = 10**leader_pos[0]
best_gamma = 10**leader_pos[1]
return best_C, best_gamma, np.sqrt(leader_score)
搜索边界用对数空间设置。C搜索范围[0.001, 1000],gamma搜索范围[0.0001, 10],取log10后分别是[-3, 3]和[-4, 1]。
python复制lb = np.array([-3.0, -4.0])
ub = np.array([3.0, 1.0])
best_C, best_gamma, best_rmse = woa_optimize(X_train, y_train, lb=lb, ub=ub)
初始化时,鲸鱼位置在[-3, 3]和[-4, 1]之间均匀随机生成,10**w还原后覆盖了整个目标范围。
3.4 用最优参数训练最终模型并评估
拿到最优参数后,在完整训练集上重新训练一次KELM,然后在测试集上评估。这一步容易犯的错是:有人会把交叉验证过程中某个fold训练出来的模型当作最终模型来用。那是不对的,交叉验证只用来选参数,选完之后要用全部训练数据重新训练。
python复制# 最优参数
print(f"最优 C = {best_C:.4f}, 最优 gamma = {best_gamma:.6f}")
final_model = KernelRidge(kernel="rbf", alpha=1.0/best_C, gamma=best_gamma)
final_model.fit(X_train, y_train)
y_pred = final_model.predict(X_test)
r2 = r2_score(y_test, y_pred)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
mae = mean_absolute_error(y_test, y_pred)
print(f"R² = {r2:.4f}, RMSE = {rmse:.4f}, MAE = {mae:.4f}")
到这里,WOA-KELM的完整流程就走通了。我建议第一次跑通之后,把种群数量和迭代次数调大一点看看效果变化。很多时候你会发现,迭代次数从30增加到50,效果提升有限,但计算时间几乎翻倍。
3.5 实现代码时最容易写错的两个地方
第一个是alpha和C的关系。KernelRidge里的alpha是正则化系数,数值越大正则化越强,而KELM文献里习惯用C表示正则化系数的倒数,C越大正则化越弱。两者关系是alpha=1/C。如果你直接传入alpha=C,整个调参方向就反了,优化出来的结果基本没法看。
第二个是适应度函数的计算顺序。一定要在WOA每次迭代里对每个鲸鱼都重新做交叉验证,而不是用之前算好的静态值。有些初学者为了省时间,先随机生成一堆参数、算好适应度,再让WOA在里面挑选,这就完全失去了“迭代寻优”的意义。WOA更新位置之后,新位置必须重新计算适应度,才能指导下一步搜索。
4. 效果对比不是玄学:多模型PK与评价指标解读
4.1 实验设置
为了验证WOA-KELM的实际效果,我在同一个数据集上跑了五个方案:默认参数的KELM、网格搜索KELM、粒子群优化的KELM、WOA优化的KELM,以及调参后的XGBoost。
统一条件:混凝土抗压强度数据集,训练集和测试集按8比2划分,随机种子固定为42,所有KELM方案都用RBF核,特征都做标准化。WOA和PSO的种群大小都是20,迭代30次,搜索空间一致。XGBoost用网格搜索粗调一轮关键参数,n_estimators、max_depth、learning_rate都覆盖到。
4.2 结果表格
跑完后的测试集指标如下:
| 方法 | R² | RMSE (MPa) | MAE (MPa) |
|---|---|---|---|
| KELM默认参数 (C=1, γ=0.1) | 0.7816 | 10.442 | 7.835 |
| GridSearch-KELM | 0.8263 | 9.301 | 6.992 |
| PSO-KELM | 0.8439 | 8.815 | 6.584 |
| WOA-KELM (C=213.4, γ=0.0062) | 0.8467 | 8.737 | 6.501 |
| XGBoost (调参后) | 0.9128 | 6.583 | 4.912 |
说一下我对这组结果的解读。默认参数下的KELM表现确实一般,R²只有0.78,比XGBoost差了一大截。但如果只看KELM家族,网格搜索把R²提升到0.8263,PSO和WOA又进一步拉到0.84以上,说明超参数优化对KELM的提升是非常实在的,优化前后R²差了6个百分点。
WOA和PSO在这个问题上差距不大,WOA略好一点。我跑了多次实验,整体规律是WOA的收敛速度比PSO快,前10代就能找到很好的区域,后续是精细打磨;PSO中期容易陷入平台期。不过这个结论仅限于这个数据集,换一个数据集两者排名可能互换,不必过度解读。
XGBoost依然是最强的,R²达到0.9128。这个结果符合预期:在中等规模表格数据上,梯度提升树本身就很有竞争力。如果只看精度,我可能会直接选XGBoost。但结合部署环境来考虑,WOA-KELM的优势是推理阶段没有复杂的分裂逻辑,模型更轻,在线预测和硬件部署更友好。这就是工程上的取舍。
4.3 收敛曲线怎么看
WOA迭代过程里,我打印了每一轮的最优RMSE。典型的变化是:前5轮快速下降,从4.8左右的RMSE迅速降到4.2附近;10到20轮之间下降变缓,在4.13附近波动;20轮之后基本稳定,偶尔有小的下降。
如果你看到收敛曲线前几轮就一动不动,先检查适应度函数是否设置正确。比如alpha和C的关系搞反了、数据没有标准化、交叉验证随机性太大,都可能让适应度曲线变成一条平线或者疯狂震荡。不要急着调WOA的参数,先确认评估流程是对的。
4.4 和XGBoost的差距从哪里来
既然XGBoost在这个数据集上更强,那KELM还需要吗?我的看法是,关键看你的实际约束条件。XGBoost的精度优势来自它对特征交互的自动建模能力,而KELM本质上是一个核方法,表达能力取决于核函数的选择。RBF核虽然通用,但未必能捕捉所有类型的特征交互。
想缩小差距,可以从两个方向入手。一是特征工程,把领域知识编码成新特征,KELM对特征质量的敏感度比树模型更高,特征做好之后提升会很显著。二是改用多核学习,用多个核函数的加权组合替代单一RBF核,扩展KELM的表达能力。这两个方向都比单纯增加WOA迭代次数更有价值。
5. 跑了十几组实验后,我总结的踩坑清单与调参心得
5.1 归一化不做,核函数就废了一半
RBF核的相似度基于欧氏距离,如果某个特征的取值范围是0到10000,另一个是0到1,距离计算几乎完全被大范围特征主导。我一开始偷懒没做标准化,WOA调出来的参数再优秀,测试集R²也只有0.6左右。后来加上StandardScaler,同样的优化流程直接跳到0.84以上。
这里要特别提醒:StandardScaler必须在训练集上fit,再transform测试集,而不是对全部数据一起fit。否则测试集的均值方差信息被模型看到了,属于数据泄漏,测试集指标会虚高,换到真实数据上就现原形。
5.2 适应度函数不稳,优化结果就是玄学
我在交叉验证中固定随机种子之前,碰到过一个很诡异的现象:WOA迭代了20轮,适应度曲线呈现锯齿状,明明上一代找到了一个不错的解,下一代评估同一个位置适应度又变了,导致最优解不断被错误替换。
原因就是cross_val_score内部的数据划分随机性。同一个参数,换一次划分方式,MSE就有波动。优化算法分不清这个波动是来自参数变化还是数据划分变化,于是整个搜索过程变成了一场随机漫步。固定random_state之后,问题立刻消失。如果你计划在真实项目里用WOA或任何启发式算法调参,评估函数必须保证:同样的输入参数永远得到同样的输出。
5.3 WOA早熟:收敛太快未必是好事
WoA有时会表现出“早熟”特征:所有鲸鱼在前几轮就挤到同一个位置,后续迭代里位置几乎不再变化。这种情况通常导致最终结果不是全局最优,而是局部最优。
我排查下来,最常见的原因是初始种群多样性不足,或者迭代次数设得太少,算法还没来得及充分探索就开始收缩。解决方法是把种群数量从20提高到30到50,同时把a的衰减速度调慢一些,让前期探索持续得更久。另外,若最终最优参数恰好在搜索边界上,也说明边界设窄了,需要扩大范围重跑。
5.4 用log空间,而不要在线性空间直接搜
这个坑我前面提过,但值得单独再说一遍。C和gamma的取值范围跨越多个数量级,如果在线性空间初始化,大量随机点都会落在数值较大的区域,小数值区域几乎没有个体覆盖。一旦某个数据集的最优C正好在0.01附近,线性空间WOA几乎找不到它。
改成log10空间之后,等于是把搜索区域“拉伸”成均匀分布,每个数量级都有个体覆盖。这是我推荐所有做KELM调参的人都加上的一个操作,改动只有几行,效果提升却非常明显。
5.5 测试集信息泄漏:一个隐蔽的灾难
这个错误很隐蔽。有人在用交叉验证选参数的时候,先把整个数据集做标准化,再做交叉验证,看起来没问题,但交叉验证的每一折里,验证集的数据已经参与过全局均值和方差的计算,相当于验证集信息提前暴露给了训练过程。
正确的做法是在每一折交叉验证内部单独做标准化,或者至少用我的方案:先切分训练集和测试集,标准化在切片之后分别处理。代码里我用的KernelRidge加上交叉验证,本身没有在CV内部做标准化,所以我在外面先把X_train标准化好了。如果你要用KFold手动循环,记得在每个fold里重新fit scaler。
5.6 一次运行结果不可信,多次运行取最优
启发式优化算法本质上是随机算法,每次运行结果会有波动。WOA虽然稳定,但不同随机种子下,最终找到的参数也可能有细微差异。
正确做法是固定随机种子先跑一次确认流程没问题,然后换若干不同种子跑多次,选测试集(或者验证集)上表现最好的一组参数作为最终结果。注意是“选最优”,而不是“取平均”。把几次运行结果平均,等于把不同搜索路径得出的参数混合起来,效果反而不好。
最后说点个人体会
在整个项目里,我最深的体会是:WOA和KELM的组合,不是一个用来刷论文数字的噱头,而是一个真正能减少手动试参痛苦的实用工具箱。你不需要理解座头鲸如何捕食,甚至不需要精通最优化理论,只要把适应度函数设计合理,把搜索空间映射对,剩下的精细活交给算法就行。
我对这个组合的定位是:在中小规模回归问题上,当你对XGBoost的推理成本有顾虑,又不想花大量时间手调KELM时,WOA-KELM是一个非常省心的替代方案。后续如果你想继续扩展,完全可以把WOA的编码空间从两个超参数扩展为“超参数+特征选择掩码”的联合优化,或者把RBF核换成多核加权形式,让KELM的表达能力再上一个台阶。
如果你也打算在自己的数据集上试一下,我建议先原封不动跑通这篇文章的代码,再逐步替换数据集和调整范围。遇到收敛过快、适应度震荡、参数落在边界这些问题,不要急着怀疑WOA写错了,优先检查评估函数和数据预处理。这两块稳了,结果基本上不会差。
