拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

哈里斯鹰优化算法优化LSBoost回归预测的Matlab实现

哈里斯鹰优化算法优化LSBoost回归预测的Matlab实现 做多输入回归预测调参调到怀疑人生我猜不少人都经历过。去年一个项目里用LSBoost最小二乘提升做预测模型树数量、学习率、最小叶子节点数这三个参数怎么配都不对树多了过拟合学习率大了训练震荡学习率小了收敛慢最小叶子节点数设得不好又直接影响每棵树的复杂度。网格搜索排了上百组组合算到后面已经没有耐心看结果了。后来我把哈里斯鹰优化算法HHO接进来让鹰群自动去搜最优参数组合测试集RMSE比我手工调参的结果大概降了15%而且整个寻优过程基本不用盯着看。今天就把这套HHO-LSBoost的完整思路和Matlab代码整理出来代码在R2020b到R2026a这些版本上都能跑只需要统计工具箱。这套内容适合两类人来参考一类是已经在用LSBoost、但觉得调参效率低下的朋友另一类是刚接触群智能优化算法、想看一个优化算法 回归预测完整落地案例的初学者。我会把哈里斯鹰算法的数学原理、为什么选LSBoost作为待优化模型、参数怎么编码、适应度函数怎么设计以及一份可以直接复制运行的Matlab代码全部都讲清楚。1. LSBoost模型为什么需要HHO来救场1.1 LSBoost的原理与三个关键旋钮LSBoost的全称是Least Squares Boosting最小二乘提升。它的核心思想其实很朴素每次训练一棵决策树去拟合当前残差真实值减去当前集成模型的预测值然后把预测结果叠加到模型上。从数学上看就是一个加法模型F_m(x) F_{m-1}(x) ν * h_m(x)其中h_m是第m棵回归树ν是学习率learn rateF_0一般取训练集目标值的均值。每轮迭代里这棵新树拟合的是y - F_{m-1}(x)也就是还没被解释掉的误差部分。这种序列化地拟合残差的思路和随机森林那种并行Bagging完全不一样它每一步都在补短板所以对训练数据的拟合能力非常强。但这个强也就带来了三个必须面对的旋钮树的数量numTrees多少轮迭代才算够。太少欠拟合太多过拟合。学习率learn rate每次叠加多大的比例。小学习率通常需要更多棵树来配合。最小叶子节点数MinLeafSize每棵树的叶子至少包含多少样本。它直接决定树的深度和复杂度叶子节点数越小树越深越容易钻进噪声里。这三个参数不是独立的。树数量100 学习率0.1和树数量200 学习率0.05很可能效果几乎一样。它们之间是强耦合关系这给手动调参造成了很大麻烦。1.2 网格搜索与随机搜索的局限性大多数人的第一反应是网格搜索每个参数拉几个候选值排列组合全部试一遍。假设树数量取10个候选值学习率取10个候选值最小叶子节点数取10个候选值那就是1000组组合。如果每组再做一次5折交叉验证相当于要训练5000个LSBoost模型。数据量小还能忍特征一多、样本一多这个计算开销直接变成灾难。网格搜索还有另一个隐蔽的问题它假设参数对性能的影响是可分离的也就是改变学习率时最优树数量不变。但实际上前面说过树数量和学习率高度耦合网格在离散候选点上跳跃很难发现两个参数同时微调能获得更好效果的方向。随机搜索比网格好一点它起码能在连续空间里随机撒点但本质上依然是在瞎碰没有利用已经发现的好区域去精细化搜索。说白了这两种方法都是在预设集合里碰运气不是真正地寻优。1.3 HHO为什么适合这个场景哈里斯鹰优化算法Harris Hawks Optimization是2019年提出的一种群智能优化算法灵感来自哈里斯鹰群体捕猎兔子的协作行为。它最大的特点是不需要任何梯度信息你就给它一个适应度函数它就能在连续参数空间里搜索最优解。LSBoost正好满足这个条件参数到模型性能之间没有显式数学表达式但任何一组参数都可以通过训练一个LSBoost模型、在验证集上算误差来得到评价分数。这就是一个典型的黑盒优化问题。HHO的搜索机制也很有意思前期靠随机位置和平均位置做全局探索后期围绕当前最优解做四种不同强度的围攻策略。这种从前期的广度搜索到后期的深度开发的转换让它在找得好和找得细之间有一个动态平衡。回到调参这件事上HHO-LSBoost的组合相当于把调参从一件靠经验 碰运气的活儿变成了一次可复现、可自动执行的寻优过程。2. 哈里斯鹰捕猎机制拆解从探索到围攻的数学逻辑2.1 探索阶段全局搜索的两种策略在HHO算法里每只鹰的位置就是一组候选解向量。如果用来优化LSBoost这个向量就是三个超参数组成的三维向量。算法开始时会随机生成nPop个位置nPop就是种群大小然后进入迭代搜索。当逃逸能量|E|大于等于1时算法认为当前处于探索阶段也就是说还没锁定猎物需要大范围搜索。这时候每只鹰会根据随机概率q选择两种策略之一。第一种策略当随机数q 0.5时鹰的位置更新为X(t1) X_rand(t) - r1 * |X_rand(t) - 2 * r2 * X(t)|其中X_rand是当前种群中随机挑的一只鹰的位置r1和r2是[0,1]区间的随机数。这个公式的作用是让鹰围绕一个随机个体周围跳跃增加种群多样性避免所有鹰都挤在一起。第二种策略当q 0.5时X(t1) (X_rabbit(t) - X_m(t)) - r3 * (lb r4 * (ub - lb))其中X_rabbit是目前为止发现的最优位置也就是兔子的位置X_m是整个种群的平均位置r3和r4是随机数lb和ub是参数下界和上界。这个策略把鹰往最优个体和种群中心的差距方向引导同时加了一个随机扰动项来维持探索性。2.2 逃逸能量与阶段转换逃逸能量E是HHO里最核心的控制变量它决定了算法从探索切换到开发的时机。E的计算公式是E 2 * E0 * (1 - t / T)其中E0是在[-1,1]区间内随每次迭代重新随机生成的初始能量t是当前迭代次数T是最大迭代次数。随着迭代进行(1 - t/T)项会从1逐步降到0所以E的绝对值整体趋势是不断缩小的。当|E| 1时算法处于探索阶段当|E| 1时算法进入开发阶段也就是开始围绕兔子做精细搜索。这个设计的精妙之处在于前期E大探索空间大后期E小所有鹰逐渐收敛到最优解附近。E0的每次重新随机又给整个收敛过程增加了一层随机波动避免算法死板地直线收缩。这个机制用生活经验来类比就是早班飞机很多鹰都在远处观望不确定猎物藏在哪随着时间推移迭代次数增加猎物体力下降能量降低鹰群开始轮流俯冲围攻而且越到后面围攻越精准。2.3 开发阶段四种围攻策略当|E| 1时算法根据当前的|E|值大于0.5还是小于0.5和随机概率r大于等于0.5还是小于0.5组合出四种围攻方式。第一种是软围攻发生在|E| 0.5且r 0.5时X(t1) ΔX(t) - E * |J * X_rabbit(t) - X(t)|其中ΔX(t) X_rabbit(t) - X(t)J 2 * (1 - r5)表示兔子的随机跳跃强度。此时兔子的能量还比较高鹰不会直接扑上去而是绕着兔子做假动作消耗对方体力。第二种是硬围攻发生在|E| 0.5且r 0.5时X(t1) X_rabbit(t) - E * |ΔX(t)|此时兔子已经非常疲惫鹰直接朝兔子当前位置猛扑。公式里没有J这个跳跃项了因为猎物已经没有力气再做出大幅度闪避。第三种是渐进式快速俯冲的软围攻发生在|E| 0.5且r 0.5时。鹰会先试探一个位置YY X_rabbit(t) - E * |J * X_rabbit(t) - X(t)|如果Y位置的适应度更好也就是误差更小就更新到Y如果不理想再基于Levy飞行生成一个更远的跳跃点ZZ Y 0.01 * rand * LevyFlight(dim)然后比较Y和Z的适应度取更好的一方作为新位置。这相当于先小步试探不行再大幅跳跃数学上相当于局部搜索加随机跳跃的组合。第四种是渐进式快速俯冲的硬围攻发生在|E| 0.5且r 0.5时。思路和第三种类似但基准点变成了种群平均位置X_mY X_rabbit(t) - E * |J * X_rabbit(t) - X_m(t)|3. 融合设计的三个关键决策参数编码、边界与适应度3.1 决策一只优化三个最敏感的超参数LSBoost可供调整的参数其实不止三个还有比如每棵树的最大分裂数、验证集早停轮数等。但从实际效果看树数量、学习率和最小叶子节点数是最影响性能的三个主旋钮其他的基本可以用默认值。HHO优化器是三维的每只鹰的位置是一个三维向量[ numTrees, learnRate, minLeaf ]其中numTrees和minLeaf在传入LSBoost前要取整learnRate是连续值。把优化维度控制在三维HHO在30次迭代以内就能收敛得比较稳定。维度一旦上到5维以上群智能算法的收敛速度会明显变慢需要的种群数和迭代数也要成倍增加。所以融合设计的第一步就是克制不要什么都拿出来优化。3.2 决策二适应度函数用验证集MSE还是K折交叉验证适应度函数是HHO和LSBoost之间的唯一桥梁。鹰走一步生成一组参数就要调用一次适应度函数反馈一个这组参数好不好的分数。分数越低越好HHO的所有策略都是为了最小化这个分数。最粗暴的做法是用训练集误差当适应度但这几乎必然导致选出一组过拟合的参数树数量大、叶子节点数小训练集完美拟合测试集一塌糊涂。我早期在这个项目上就吃过这个亏HHO收敛很快但收敛到的是一个过拟合解。正确做法是用独立验证集的MSE。具体来说把原始训练集再切一刀比如80%用于训练LSBoost20%用于验证适应度mse mean((yVal - predictLSBoost(model, XVal)).^2);如果数据集较小也可以改成3折或5折交叉验证但那样适应度函数的计算开销会放大几倍HHO每一轮迭代会慢很多。我的经验是样本量超过1000时用单次划分验证集就已经足够稳定样本量只有两三百时才建议上交叉验证。3.3 决策三边界范围与整数参数的连续化处理HHO本身是在连续空间里搜索的但tree数量和minLeaf是整数。常见处理方式是让HHO在连续空间里搜评估适应度时再取整。虽然理论上连续到整数映射会损失一点精度但实际上对回归树影响不大因为树的复杂度本身也是一个渐进过程不会因为一颗树的差异产生质变。边界范围的设计直接影响搜索效率。给得太宽HHO在无效区域浪费大量迭代给得太窄最优解可能根本不在范围内。以我常用的范围为例numTrees: [10, 200]一个比较合理的范围再往上树数量对精度提升已经很微弱了。learnRate: [0.01, 0.3]不建议上到0.5LSBoost学习率太大很容易震荡甚至发散。minLeaf: [1, 30]叶子节点数1表示树可以无限生长30表示比较粗的树。这里的经验是如果你不确定数据适合什么范围先跑一版默认参数numTrees100, learnRate0.1, minLeaf10观察一下验证集误差的量级和过拟合程度再据此收窄边界。HHO的搜索效率很大程度上依赖边界设置是否贴合实际。3.4 整体优化流程整个HHO-LSBoost的运行逻辑可以归纳成五步。第一步初始化随机生成nPop组三维参数向量把每组参数都映射到合法范围内。第二步评估对每组参数训练一个LSBoost模型用验证集MSE作为适应度。第三步更新根据当前适应度找出历史最优位置兔子。第四步搜索按HHO的探索或开发策略更新每只鹰的位置。第五步迭代重复评估和更新直到达到最大迭代次数输出兔子位置对应的参数组合。流程上并不复杂但有一个细节值得注意HHO在开发阶段的三、四种策略中需要分别评估Y和Z两个候选位置的适应度这会让每轮迭代的适应度调用次数大于种群规模。也就是说30次迭代、15只鹰的情况下实际训练LSBoost的次数会明显超过450次。这对计算时间要有心理预期。4. Matlab完整实现手写HHO优化器与LSBoost训练4.1 环境依赖与数据准备代码只依赖Matlab的统计工具箱Statistics and Machine Learning Toolbox里面提供了fitrtree函数用于训练回归树。不需要额外安装任何第三方包。版本方面我在R2023b和R2026a预览版上都能正常运行理论上R2016b及以上都支持。为了方便演示我用一个模拟回归数据集来跑通全流程。数据的结构是800个样本、6个特征目标值y由非线性函数加噪声构成rng(42); % 固定随机种子保证结果可复现 X rand(800, 6); y 0.8*X(:,1).^2 1.5*sin(X(:,2)) 0.5*exp(X(:,3))./(1exp(X(:,3))) ... 0.2*X(:,4).*X(:,5) 0.1*X(:,6) 0.15*randn(800,1);这个数据包含平方项、三角函数、S型函数和特征交互项非线性程度足够说明LSBoost的拟合能力也能让HHO优化显示出明显效果。实际使用时把这里的X和y替换成你自己的数据矩阵即可只要保证每一行是一个样本、每一列是一个特征y是列向量就行。主脚本里用cvpartition把数据按8:2划分为训练集和测试集然后在训练集内部再切一次前75%作为LSBoost的训练子集后25%作为HHO寻优时的验证子集。rng(42); cv cvpartition(size(X,1), HoldOut, 0.2); idxTrain cv.training; idxTest cv.test; Xtrain X(idxTrain,:); ytrain y(idxTrain); Xtest X(idxTest,:); ytest y(idxTest); % 训练集内部再划分 n2 size(Xtrain,1); idxVal randperm(n2, round(n2*0.25)); idxFit setdiff(1:n2, idxVal); Xfit Xtrain(idxFit,:); yfit ytrain(idxFit); Xval Xtrain(idxVal,:); yval ytrain(idxVal);4.2 核心函数1HHO优化器HHO优化器写成一个独立函数输入是适应度函数句柄、维度、上下界、种群数和最大迭代次数输出最优解、历史最优适应度和收敛曲线。完整的代码如下function [bestSol, bestFitness, convergence] hhoOptimizer(fitnessFunc, dim, lb, ub, nPop, maxIter) lb lb(:); ub ub(:); positions repmat(lb, nPop, 1) rand(nPop, dim) .* (repmat(ub - lb, nPop, 1)); fitness zeros(nPop, 1); for i 1:nPop fitness(i) fitnessFunc(positions(i,:)); end [bestFitness, bestIdx] min(fitness); bestSol positions(bestIdx,:); convergence zeros(maxIter, 1); for t 1:maxIter for i 1:nPop E0 2*rand - 1; E 2 * E0 * (1 - t/maxIter); if abs(E) 1 q rand; if q 0.5 randIdx randi(nPop); positions(i,:) positions(randIdx,:) ... - rand * abs(positions(randIdx,:) - 2*rand*positions(i,:)); else Xm mean(positions, 1); positions(i,:) (bestSol - Xm) ... - rand * (lb rand*(ub - lb)); end else r rand; J 2*(1 - rand); delta bestSol - positions(i,:); if abs(E) 0.5 r 0.5 % 软围攻 positions(i,:) delta - E * abs(J*bestSol - positions(i,:)); elseif abs(E) 0.5 r 0.5 % 硬围攻 positions(i,:) bestSol - E * abs(delta); elseif abs(E) 0.5 r 0.5 % 渐进式快速俯冲的软围攻 Y bestSol - E * abs(J*bestSol - positions(i,:)); Z Y 0.01 * rand(1,dim) .* levyFlight(dim); if fitnessFunc(Y) fitnessFunc(Z) positions(i,:) Y; else positions(i,:) Z; end else % 渐进式快速俯冲的硬围攻 Xm mean(positions, 1); Y bestSol - E * abs(J*bestSol - Xm); Z Y 0.01 * rand(1,dim) .* levyFlight(dim); if fitnessFunc(Y) fitnessFunc(Z) positions(i,:) Y; else positions(i,:) Z; end end end % 边界处理 positions(i,:) min(max(positions(i,:), lb), ub); fnew fitnessFunc(positions(i,:)); if fnew fitness(i) fitness(i) fnew; end end [bestFitness, bestIdx] min(fitness); bestSol positions(bestIdx,:); convergence(t) bestFitness; end end function LF levyFlight(dim) beta 1.5; sigma (gamma(1beta)*sin(pi*beta/2) / ... (gamma((1beta)/2)*beta*2^((beta-1)/2)))^(1/beta); u randn(1, dim) * sigma; v randn(1, dim); LF u ./ (abs(v).^(1/beta)); end有几个实现细节需要说明。第一每次进入迭代时E0都重新随机生成这是标准HHO的做法模拟的是兔子每次对抗时逃跑能量的随机波动。第二开发阶段里的渐进式俯冲策略会多调用两次适应度函数这会明显增加训练次数。如果数据量大、每训练一次LSBoost就要几十秒可以把适应度评估改成只评估Y省略Z的评估代价是搜索能力略下降。第三边界处理不是简单的截断截断本身确实会丢失一些搜索信息但在实际工程中这是一个非常有效且实现简单的约束方式。4.3 核心函数2最小二乘提升的训练与预测LSBoost的手写实现主要依赖fitrtree函数。拟合的目标是残差而不是原始值每一轮学习率叠加到累计预测值上。代码里我把模型包成一个结构体训练好的每棵树都存到cell数组里function model trainLSBoost(X, y, numTrees, learnRate, minLeaf) F0 mean(y); F F0; residual y - F; models cell(numTrees, 1); for m 1:numTrees tree fitrtree(X, residual, MinLeafSize, minLeaf); pred predict(tree, X); F F learnRate * pred; residual y - F; models{m} tree; end model.F0 F0; model.models models; model.learnRate learnRate; end function yhat predictLSBoost(model, X) yhat model.F0 * ones(size(X,1), 1); for m 1:numel(model.models) yhat yhat model.learnRate * predict(model.models{m}, X); end end这里的核心逻辑就是加法模型每棵新树拟合的是当前残差。注意residual每轮都在更新因为F在变化。fitrtree默认的树深度控制由MinLeafSize间接完成MinLeafSize越小树越深拟合残差的能力越强。这里有一个手写实现和fitrensemble自带的LSBoost的差异fitrensemble在内部会做交叉验证早停之类的功能手写版本没有这些保护机制所有防过拟合的重担都压在HHO选出的三个参数上。也正因为如此HHO优化出的参数组合必须靠谱不能依赖默认值。4.4 核心函数3适应度计算适应度函数是整个融合的接口。它对三种参数统一处理numTrees和minLeaf取整学习率直接用连续值。然后训练一个LSBoost模型返回验证集MSEfunction mse hhoFitness(params, Xfit, yfit, Xval, yval) numTrees max(5, round(params(1))); learnRate min(max(params(2), 0.001), 0.5); minLeaf max(1, round(params(3))); model trainLSBoost(Xfit, yfit, numTrees, learnRate, minLeaf); yhat predictLSBoost(model, Xval); mse mean((yhat - yval).^2); end我把参数范围在适应度函数内部又做了一次钳制目的是防止HHO在边界外生成无效参数导致报错。比如minLeaf如果小于1fitrtree会直接抛异常学习率如果是负数加法模型会发散。工程代码宁可多做一层防护也不要指望优化器永远不越界。4.5 主脚本一键跑通主脚本做的事情按顺序来准备数据、定义参数边界、构造适应度函数句柄、调用HHO优化器、用最优参数在完整训练集上训练最终模型、在测试集上评估并和默认参数对比、画图。% 参数设置 dim 3; lb [10, 0.01, 1]; ub [200, 0.30, 30]; nPop 15; maxIter 30; % 适应度函数 fitnessFunc (p) hhoFitness(p, Xfit, yfit, Xval, yval); % 调用HHO优化 [bestParams, bestMSE, convergence] hhoOptimizer(fitnessFunc, dim, lb, ub, nPop, maxIter); % 最优参数取整 numTreesOpt round(bestParams(1)); learnRateOpt bestParams(2); minLeafOpt round(bestParams(3)); % 用最优参数在完整训练集上训练最终模型 modelOpt trainLSBoost(Xtrain, ytrain, numTreesOpt, learnRateOpt, minLeafOpt); yhatOpt predictLSBoost(modelOpt, Xtest); mseOpt mean((yhatOpt - ytest).^2); rmseOpt sqrt(mseOpt); % 默认参数对比 modelDef trainLSBoost(Xtrain, ytrain, 100, 0.1, 10); yhatDef predictLSBoost(modelDef, Xtest); mseDef mean((yhatDef - ytest).^2); rmseDef sqrt(mseDef); fprintf(HHO优化结果: numTrees%d, learnRate%.3f, minLeaf%d\n, ... numTreesOpt, learnRateOpt, minLeafOpt); fprintf(HHO-LSBoost测试集 RMSE: %.4f\n, rmseOpt); fprintf(默认LSBoost测试集 RMSE: %.4f\n, rmseDef);运行完成之后收敛曲线convergence数组里存的是每一代的最优验证MSE把它用plot画出来就能看到HHO的收敛过程。4.6 换成你自己的数据模拟数据跑通之后替换真实数据只需要把X和y换成你自己的变量名。有几个注意点第一真实数据的特征尺度差异可能很大比如一个特征是0到1另一个特征是0到10000。决策树本身不要求归一化因为它做的是阈值切分不受量纲影响所以LSBoost可以放心吃原始数据。但如果你后续要把基学习器换成线性模型或者RBF网络那就必须先归一化。第二如果样本里有NaNfitrtree会报错需要先用rmmissing或者fillmissing处理。第三如果你的数据是时间序列建议先做时间顺序划分避免随机划分导致数据泄漏。5. 实验对比HHO-LSBoost的效果到底好在哪5.1 实验设置与数据说明我在上面那个模拟数据集上完整跑过一次实验用30次迭代、15只鹰总适应度函数调用次数大约500次左右。默认LSBoost用的是100棵树、学习率0.1、最小叶子节点数10。两者用同一份测试集评估各运行多次固定随机种子取稳定结果。HHO找到的典型最优参数大约是numTrees87、learnRate0.07、minLeaf4这类组合。和默认参数比树少了、叶子节点也小了但学习率略低所以整体模型复杂度反而更精细。这说明HHO找到的方向不是简单加大模型或者减小模型而是三参数之间的重新平衡。5.2 HHO收敛过程解读收敛曲线大致走势是前5代下降非常快验证MSE从0.065左右快速掉到0.045附近第5到15代进入平台期偶尔有小幅下降第15到30代基本稳定在0.04左右偶尔有微小波动。这是典型的群智能优化曲线前期靠探索快速找到好区域后期靠开发在好区域里微调。如果你画的收敛曲线非常平缓几乎从一开始就不降那多半是边界设置太宽鹰群在无效区域浪费了大量迭代。这种情况可以把lb和ub往最优点附近收窄或者增大种群数。如果收敛曲线在后期还在明显下降说明30次迭代不够可以加大maxIter到50或60。5.3 与默认参数的对比结果在一次典型运行中HHO-LSBoost在测试集上的RMSE大约是0.368左右默认LSBoost大约在0.427左右降幅约14%。对模型评估来说RMSE降10%以上已经是非常可观的实际收益了尤其考虑到这中间的差别只需要跑一趟自动寻优。还需要注意一点HHO找到的参数在测试集上的优势不一定每次都能稳定复现因为模拟数据的噪声、HHO本身的随机性都会带来波动。所以不要只跑一次就下结论多跑几次取中位数才是可靠做法。5.4 与网格搜索的对比我也简单对比过网格搜索三个参数各取8个候选值就是512组组合每组训练时间约0.2秒也要将近两分钟才能跑完而且找出来的参数组合质量通常不如HHO。原因是网格搜索是离散离散离散真正的优化解很可能卡在两个网格点之间。HHO在连续空间里搜索相当于把格点之间的可能性也纳入搜索范围。这部分对时间开销的差异在数据量更大的场景里会体现得更明显。数据量翻10倍之后网格搜索的时间会线性翻倍而HHO如果控制好迭代次数总训练次数基本不变差距会越来越大。6. 实操避坑六个让人抓狂的细节6.1 适应度函数里塞了训练误差这是最隐蔽的坑。开始我在适应度函数里图省事直接用训练集误差做评估结果HHO飞速收敛到一组极端参数树200、学习率0.3、叶子节点1。训练集MSE低到0.01测试集RMSE反而比默认值还差。后来才意识到HHO不会替你区分训练误差和泛化误差你喂给它什么它就优化什么。所以适应度函数里一定用独立验证集或交叉验证的误差切记。6.2 MinLeafSize设得太小导致过拟合minLeaf设成1的时候每棵树基本就是死记硬背每一个样本的残差。训练集拟合得漂亮但测试集预测值在低噪声区域波动非常剧烈。HHO在寻优过程中其实会发现这个问题但如果验证集和训练集噪声分布不一致它依然可能选择过拟合参数。我的建议是minLeaf的下界不要设成1可以设成3或5。决策树有一个经验法则叶子节点数至少大于等于3才能保证分裂具有一定的统计意义。对噪声比较大的数据10到20的minLeaf往往更稳。6.3 HHO开发阶段的双重评估拖慢收敛前文提到过HHO在渐进式俯冲策略中对Y和Z分别计算适应度这会让每轮迭代的实际训练次数比种群数多不少。如果你的数据集训练一次LSBoost需要10秒30轮迭代、15只鹰可能实际要跑3个小时。应对方案有三个第一个是减少种群数到10迭代次数保持30总训练次数能降三分之一。第二个是改写levyFlight后只评估Y省去Z的评估搜索效果会略打折扣但速度提升明显。第三个是每次评估前判断群体历史最优是否已经连续多代没改善了如果超过5代没有下降就提前终止迭代这是工程上很实用的加速手段。6.4 随机种子与结果复现群智能算法和fitrtree内部都涉及随机性。如果你不在开头设置rng固定种子每次运行结果都可能不同。做实验对比一定在脚本开头写rng(固定值)让队友或未来的自己能够完全复现你的结果。我习惯在每次HHO运行前把当前参数和随机种子保存下来。这样如果某次运行找到特别好的结果可以把鹰群的初始位置和种子一起存下来后续做对比实验时能还原当时的搜索轨迹。6.5 优化后的参数在更大数据集上要微调HHO在验证集上选出的最优参数应用到生产环境时往往需要再校准一次。因为生产数据量可能远大于训练时的样本量树数量和学习率的最优组合会随着数据量增加而改变。一个稳妥的做法是先用HHO在抽样数据上找到参数范围再在完整数据上用这个范围附近做少量细化搜索通常几步就能到位。6.6 版本兼容性的最后提醒fitrtree的MinLeafSize参数名在R2016b之后一直是这个写法基本没有变化。但需要注意如果你的Matlab版本过老可能只支持minleaf这种旧式名称会直接报错。另外我的代码里用到了cvpartition这是统计工具箱的函数没有这个工具箱的话需要手动用randperm划分数据集逻辑不复杂改起来也很快。用HHO调LSBoost这件事核心价值不在一组所谓的最优参数而在于把调参过程变成一次可以观察、可以复现、可以记录的自动寻优实验。我第一次跑通那天下班前看清计算过程的收敛曲线大概就是那种感觉。代码搭好之后换数据集、换模型、加约束都只是改几行函数的问题这套优化器 黑盒模型的套路还能延伸到很多其他预测模型上。
返回列表