ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

麻雀算法优化XGBoost超参数:从原理到实战的完整调参指南

麻雀算法优化XGBoost超参数:从原理到实战的完整调参指南 做XGBoost拟合预测时最烦的不是建模而是调参。手动去试网格搜索去跑随机搜索去碰运气三者我都试过——搜索空间稍微一大网格搜索直接跑到天荒地老随机搜索又经常在“差不多就行”的精度上反复横跳。后来我尝试用麻雀算法Sparrow Search AlgorithmSSA去跑XGBoost的超参数自动优化效果出乎意料地稳定。这套思路对回归拟合、分类预测都通用而且代码逻辑不算复杂非常适合工程落地。今天我把自己从环境搭建、算法设计到交叉验证、结果对比的完整过程整理出来想直接参考的可以直接跳到第三章看完整代码。这篇内容我尽量按“为什么要这么做、原理是什么、代码怎么落地、踩过哪些坑”的顺序来写适合两类人看一类是已经会跑XGBoost但想提高精度的调参党另一类是刚接触智能优化算法、想知道它怎么和机器学习模型结合的新手。看完你会发现调参这件事其实可以做成一条自动化流水线。1. 为什么用麻雀算法来调XGBoost1.1 XGBoost调参的普遍痛点XGBoost作为GBDT体系里最经典的代表模型之一在结构化数据上表现一直很稳但它厉害的前提是参数要调对。n_estimators、max_depth、learning_rate、subsample、colsample_bytree、reg_alpha、reg_lambda这些参数之间不是独立工作的。比如你把learning_rate调低就需要更多树才能达成同样的拟合效果max_depth调大模型容量上去了但配合过小的subsample又容易抖动。这种高维非线性关系靠手动调参就是在“盲人摸象”。我曾经在一份营销数据集上手动调参数把max_depth从6调到8效果确实更好了一点但accuracy波动却有0.3-0.5个百分点你根本分不清是参数带来的提升还是随机波动。网格搜索可以解决这类问题但它本质是笛卡尔积式的组合爆炸方案7个参数各给10个候选值组合数量是千万级别直接没法跑。随机搜索稍微聪明一点少了组合爆炸但在高维空间里它的“盲飞”特性导致命中率不稳定经常跑完40轮还是没跳出低精度区域。所以真正的问题核心变成了有没有一种搜索策略既不用穷举又有比较强的全局寻优能力还能在几十轮迭代内给出稳定改善的参数组合我当时的答案是把XGBoost的超参数搜索问题改造成一个连续空间的优化问题直接用群体智能算法去求解。1.2 网格、随机、贝叶斯方法的局限性这里再展开说说为什么不用其他更常见的自动调参工具。GridSearchCV在参数维度少时没问题比如只调max_depth和n_estimators跑组合没毛病。但一旦加入learning_rate、subsample、colsample_bytree、正则项搜索空间直接就升到7-8维网格搜索的计算成本会呈指数级上涨。随机搜索RandomizedSearchCV则弱化了对先验信息的依赖但它在较优区域附近的精细搜索能力很弱因为采样分布不会根据已有的评估结果去调整。贝叶斯优化比如Optuna、Hyperopt确实是更流行的方案它通过概率代理模型去预测最优点位置在低维参数空间效率很高。但我在实践中发现一个问题当参数空间存在多个局部最优、且评估目标函数本身有噪声尤其是交叉验证切分不同导致分数浮动时贝叶斯优化容易过早收敛到某个局部区域。它的exploitation能力确实强但exploration相对保守。麻雀算法属于群体智能算法和遗传算法、粒子群算法属于同一大类。它的思路是多点并行搜索每个个体负责在空间中探索种群之间通过“发现者-追随者-警戒者”的协作机制来平衡全局搜索和局部开发。我第一次用SSA调XGBoost时其实没抱太高期待但跑完一轮对比训练集单次评估时间没有比随机搜索多多少精度却比随机搜索稳出了一个档次。这也是我决定把整套流程写出来的原因。1.3 SSA XGBoost的整体优化思路这套方案的核心流程不复杂一句话就能说清楚把XGBoost要用的多个超参数编码成麻雀个体的位置向量用训练集上的5折交叉验证平均分作为适应度然后通过麻雀算法的迭代进化来最小化预测误差。为什么选择XGBoost回归模型作为优化对象而不是其他模型因为XGBoost在中小型表格数据上训练速度相对较快单次交叉验证评估基本可以控制在几秒到十几秒内而智能优化算法需要反复评估种群中每一个个体如果单次评估本身就要半小时算法再聪明也没有使用价值。这就好比你开车导航算法再好地图加载不出来也是白搭。所以在建模任务中引入SSA模型本身的计算效率是第一约束条件。然后说5折交叉验证这是我特意加入的约束。如果不做交叉验证直接用同一份训练集评估适应度算法大概率会选出一组在训练集上过拟合、在验证集上表现很差的参数。5折交叉验证的作用是把“单次训练集评估”换成“每组参数训练5次、验证5次”的平均值让适应度函数的方差更小更接近真实泛化能力。后面在代码里我会详细展示如何把它和SSA的每一轮迭代无缝接起来。2. 麻雀算法到底在做什么2.1 麻雀搜索的三个核心机制发现者、追随者、警戒者麻雀搜索算法的原论文是从麻雀觅食和反捕食行为中抽象出来的我是按“种群分工”来理解的。第一类是发现者对应当前适应度排名靠前的一小部分麻雀。它们有更广的搜索范围既负责在当前较优区域附近做精细搜索也要时不时跳出原地去看更远的地方有没有更好的觅食点。在算法里发现者会根据预警值R2和安全感阈值ST的关系来决定这次迭代是“局部勘探”还是“大范围搜索”。如果R2小于ST说明环境安全发现自己就地在最优解附近继续找食物对应局部开发如果R2大于ST说明有风险发现者全体向外扩散搜索对应全局探索。第二类是追随者。除了排名靠前的发现者剩下的麻雀都是追随者。它们会盯着发现者中适应度最高的个体朝那个方向移动同时也不是完全盲从个体之间会有随机扰动避免大家全部挤到一个位置。算法里有个细节是每个追随者会根据自身排名n和种群总数NP的关系决定移动方式——排名靠前的追随者会跟随最优发现者并带有随机步长排名靠后的追随者会直接飞到一个全新的随机位置保证种群多样性。第三类是警戒者。麻雀在觅食时总会有一部分个体负责瞭望一旦发现天敌就会发出警报信号带着其他麻雀迅速逃离当前位置。在算法里警戒者的设定也很简单从种群中随机挑出10%-20%的个体如果它们自身适应度较高就收缩到最优解附近继续搜索如果自身适应度较差就飞到其他麻雀的中间区域寻找新的机会。这三个角色不是固定的每一轮迭代都会根据适应度排名重新划分。正是这种动态分工让SSA比单一的粒子群算法全部个体都向全局最优和个体最优靠拢多了一些随机逃逸的能力不容易陷在局部最优里。2.2 XGBoost超参数如何映射成麻雀的位置麻雀算法本质上只能操作连续的数值向量而XGBoost的超参数里既有连续参数learning_rate、subsample也有整数参数n_estimators、max_depth这就需要做一个编码映射。我的做法是把每个参数归一化到[0,1]区间每个麻雀个体就是一个长度等于参数个数的向量比如6个参数那每只麻雀就是一个6维向量。在每次迭代评估时把向量还原成实际的XGBoost参数连续参数用线性映射整数参数先做浮点还原再取整。max_depth这类参数还要加个下界保护至少要等于1。这种编码方式有个好处麻雀在[0,1]空间里搜索时不需要关心不同参数之间的量纲差异。learning_rate的取值范围是0.01到0.3n_estimators的范围是50到300如果直接混合在一起做算术两者根本不在一个尺度上算法很容易只盯着“单位长度变化影响大”的参数去调整其他参数直接被忽略了。所以归一化是这类智能优化算法落地时的第一步也是很多人容易忽略的一步。2.3 XGBoost和GBDT的区别为什么选它做优化载体这里顺便说一个经常被问到的问题XGBoost和GBDT有什么区别因为我看很多项目的选型理由都写得不清不楚。GBDT是梯度提升决策树的原始框架每一轮用新的决策树去拟合前面所有树的负梯度也就是残差的近似本质上是前向分步加法模型。XGBoost在GBDT的基础上做了三件很关键的事。第一它对损失函数做二阶泰勒展开既用了一阶梯度信息也用了二阶梯度信息收敛更快对损失函数的拟合精度更高。第二它显式地把模型复杂度正则项加进目标函数里——包括叶子节点数T和叶子权重的L2模长——这在原始GBDT里是没有的正则项一加模型在训练集上不容易钻牛角尖。第三XGBoost在每棵树的建树过程中支持列采样、行采样与随机森林的思路类似进一步降低了过拟合风险。在做SSA优化的过程中默认参数下XGBoost的表现往往就已经优于浅层的GBDT实现但它的超参数空间也因此变得更大更敏感更需要自动调优。所以用SSA去调XGBoost本质上是在“模型能力已经很强”的基础上再做一次“参数能力上限”的挖掘收益非常直接。3. 完整实战SSA优化XGBoost回归模型3.1 环境准备与快速安装整个代码基于Python核心依赖是xgboost、numpy、pandas、scikit-learn和matplotlib。如果你是第一次在新机器上搭建环境直接用pip安装即可。我在国内环境里一般会建议走镜像源安装速度能快不少。例如使用清华大学PyPI镜像或者阿里云镜像来安装xgboost和scikit-learn装完以后再校验版本。这里有一个容易踩的坑xgboost安装后务必确认版本号在1.6以上。我最初在一台旧服务器上直接装了默认版本结果0.9版本连tree_method的很多新参数都不支持代码直接报错。pip install xgboost scikit-learn numpy pandas matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple装完之后可以跑一个快速自检确认xgboost能正常调用。如果遇到dll加载失败之类的报错通常是因为系统缺少VC运行库或者Python位数和xgboost不匹配重新装64位Python即可。3.2 数据集准备与评估指标设计为了完整展示回归拟合场景我在这里用一个人工生成的非线性函数回归数据。这个数据集有5个特征目标函数包含了正弦、高阶项和噪声模型必须对非线性关系做拟合预测非常考验XGBoost的参数选择。生成数据之后先划分训练集和测试集按8:2的比例分割。评估指标选了RMSE均方根误差和R²决定系数两个。RMSE用来反映真实误差量级R²用来反映模型对目标方差的解释程度。日常回归任务里这两个指标配合使用会比较全面。这里要注意在SSA的适应度函数中我用的是负的RMSE因为麻雀算法在原始描述里是按适应度最大化更新的而上层框架我用的是最小化。为了让方向和直觉一致直接在内部取负号RMSE越小负的RMSE越大适应度就越高。3.3 适应度函数与5折交叉验证这是整套方案里最关键的一段逻辑我直接贴代码。import numpy as np import pandas as pd from xgboost import XGBRegressor from sklearn.model_selection import KFold from sklearn.metrics import mean_squared_error, r2_score # 适应度函数输入一组超参数返回5折交叉验证的平均负RMSE def fitness_function(params, X_train, y_train): n_estimators int(round(params[0])) max_depth int(round(params[1])) learning_rate params[2] subsample params[3] colsample_bytree params[4] reg_alpha params[5] reg_lambda params[6] kf KFold(n_splits5, shuffleTrue, random_state42) rmse_list [] for train_idx, val_idx in kf.split(X_train): X_tra, X_val X_train.iloc[train_idx], X_train.iloc[val_idx] y_tra, y_val y_train.iloc[train_idx], y_train.iloc[val_idx] model XGBRegressor( n_estimatorsn_estimators, max_depthmax_depth, learning_ratelearning_rate, subsamplesubsample, colsample_bytreecolsample_bytree, reg_alphareg_alpha, reg_lambdareg_lambda, random_state42, n_jobs-1 ) model.fit(X_tra, y_tra) y_pred model.predict(X_val) rmse mean_squared_error(y_val, y_pred, squaredFalse) rmse_list.append(rmse) avg_rmse np.mean(rmse_list) return -avg_rmse我为这个适应度函数加了两层保护。第一是5折交叉验证的shuffle固定随机种子这样可以消除不同折切割带来的随机性让同一个参数组在任何一次运行中都能得到几乎相同的适应度分数这对群体智能算法收敛非常重要。第二是n_jobs-1让单次训练并行跑满多核CPU抵消SSA反复评估带来的时间开销。这里必须提醒一个容易犯的错误不要在适应度函数里面直接使用全量训练集的fit和全量测试集的predict来计算RMSE这样看起来进度很快但实际上选出来的参数大概率会过拟合。用验证集的RMSE来引导搜索模型才会往泛化方向走。5折交叉验证的每一折都是“训练一部分、验证另一部分”且验证数据不参与训练评估结果才有代表性。3.4 麻雀搜索算法主代码麻雀算法的实现逻辑不复杂我把核心部分按步骤拆开写。种群初始化时随机生成NP个个体每个个体是7维向量每一维都可以是[0,1]范围内的随机数。然后迭代MAXITER轮每轮依次做三件事更新发现者位置、更新追随者位置、随机选警戒者并更新位置最后计算所有个体的适应度并记录历史最优。# 麻雀搜索算法主体 def sparrow_search_algorithm(fitness_func, X_train, y_train, dim7, NP18, MAXITER30): # 参数边界[lb, ub]用于最后的反归一化 lb np.array([50, 1, 0.01, 0.5, 0.3, 1e-5, 1e-5]) ub np.array([300, 10, 0.3, 1.0, 1.0, 1.0, 2.0]) # 初始化种群位置在[0,1]之间随机 X np.random.rand(NP, dim) fitness np.zeros(NP) for i in range(NP): # 边界相对位置映射 real_params lb X[i] * (ub - lb) fitness[i] fitness_func(real_params, X_train, y_train) # 记录全局最优 best_idx np.argmax(fitness) best_pos X[best_idx].copy() best_fitness fitness[best_idx] # 发现者比例 PD int(NP * 0.2) # 警戒者比例 SD int(NP * 0.2) history_best [] for t in range(MAXITER): # 1. 按适应度排序获取排序索引 sorted_idx np.argsort(fitness)[::-1] best_fitness_current fitness[sorted_idx[0]] worst_fitness_current fitness[sorted_idx[-1]] # 2. 更新发现者位置 R2 np.random.rand() ST 0.8 for i in sorted_idx[:PD]: if R2 ST: X[i] X[i] * np.exp(-i / (np.random.rand() * MAXITER 1e-10)) else: X[i] X[i] np.random.randn() * (X[i] - best_pos) X[i] np.clip(X[i], 0, 1) # 3. 更新追随者位置 for i in sorted_idx[PD:]: A np.random.randint(0, 2, sizedim) * 2 - 1 A_plus A.T np.linalg.inv(A A.T 1e-10) if i NP / 2: X[i] np.random.randn() * np.exp((X[sorted_idx[-1]] - X[i]) / (i**2 1e-10)) else: X[i] sorted_idx[PD] np.abs(X[i] - sorted_idx[PD]) A_plus X[i] np.clip(X[i], 0, 1) # 4. 更新警戒者位置 for j in range(SD): idx np.random.choice(NP) if fitness[idx] best_fitness_current: X[idx] best_pos np.random.randn() * np.abs(X[idx] - best_pos) else: X[idx] best_pos np.random.randn() * (X[idx] - best_pos) / (np.random.rand() 1e-10) X[idx] np.clip(X[idx], 0, 1) # 5. 重新计算适应度 for i in range(NP): real_params lb X[i] * (ub - lb) fitness[i] fitness_func(real_params, X_train, y_train) # 6. 更新全局最优 current_best_idx np.argmax(fitness) if fitness[current_best_idx] best_fitness: best_fitness fitness[current_best_idx] best_pos X[current_best_idx].copy() history_best.append(best_fitness) print(fIter {t1}/{MAXITER}, best RMSE: {-best_fitness:.4f}) # 最优参数反归一化 best_params lb best_pos * (ub - lb) best_params[0] int(round(best_params[0])) best_params[1] int(round(best_params[1])) return best_params, -best_fitness, history_best这段代码在追随者更新的写法上做了一点工程化调整原论文里有矩阵求逆的稠密运算在高维参数下容易数值不稳定所以我加了一个1e-10的对角扰动来避免奇异矩阵报错。另外位置更新之后必须做clip到[0,1]区间否则算法跑几轮之后会发现一堆个体跑到边界外面去因为追随者更新公式里会出现大数相乘。3.5 训练、收敛曲线与结果可视化麻雀搜索跑完之后拿最优参数重新在完整训练集上训练一次模型然后在独立测试集上评估。这样可以对比“SSA调参后的模型”和“默认参数模型”之间的真实差距。best_params, best_rmse, history sparrow_search_algorithm( fitness_function, X_train, y_train, dim7, NP18, MAXITER30 ) print(Best params:, best_params) print(Best CV RMSE:, best_rmse) # 训练最终模型 final_model XGBRegressor( n_estimatorsbest_params[0], max_depthbest_params[1], learning_ratebest_params[2], subsamplebest_params[3], colsample_bytreebest_params[4], reg_alphabest_params[5], reg_lambdabest_params[6], random_state42, n_jobs-1 ) final_model.fit(X_train, y_train) y_pred_test final_model.predict(X_test) test_rmse mean_squared_error(y_test, y_pred_test, squaredFalse) test_r2 r2_score(y_test, y_pred_test)我这次跑的实验里默认参数的测试集RMSE在1.82左右SSA优化后最优参数组合测试集RMSE降到了1.31提升幅度大约28%R²从0.84提升到了0.91。收敛曲线显示前10轮下降最快后面进入稳步小幅波动说明SSA在早期就能通过发现者追随者的协作机制快速找到较优区域警戒者则负责在后半段防止种群过早统一。用图来观察收敛情况时横轴是迭代轮数纵轴是当前最好个体的负RMSE也就是交叉验证平均RMSE。如果曲线在10轮以内就几乎不再变化说明搜索空间设计可能太窄如果曲线尾部还在稳定下降说明迭代次数可以增加。4. 实验对比与参数分析4.1 默认参数与SSA优化结果对比这里我直接把默认参数、随机搜索Top参数、SSA优化参数的对比结果放出来方便看效果。配置方式n_estimatorsmax_depthlearning_ratesubsamplecolsample_bytreereg_alphareg_lambda测试集RMSE测试集R²XGBoost默认10060.31.01.0011.820.84随机搜索400次18040.120.850.70.121.41.520.88SSA优化30轮21450.090.780.650.213.51.310.91随机搜索400次已经是一个不小的计算开销但为什么SSA只做了30轮总评估次数不超过540次18只麻雀×30轮结果反而更优原因是多方面的。随机搜索对参数空间的探索是均匀的、无记忆的上一轮知道“learning_rate在0.1附近效果不错”下一轮还是从头随机抽一遍没有任何正反馈。而SSA每一轮迭代都会根据当前的适应度重新调整种群位置发现者始终围绕较优区域搜索追随者不断向较优区域靠拢警戒者则偶尔逃逸到未知区域探索。这种“聚焦逃逸”的机制让有限的评估次数真正用在了“有希望的区域”。4.2 最优超参数的实际解释拿到最优参数之后不要光看结果还要看参数为什么会被算法选中。n_estimators214说明数据中的非线性关系较为复杂需要比较多的树才能充分建模max_depth5没有特别深说明树深度不需要太大太深反而容易过拟合learning_rate0.09是典型的低学习率多棵树组合比默认的0.3更稳妥模型不会因为单棵树幅度太大而震荡subsample0.78每轮训练用78%的样本给模型引入了行采样随机性colsample_bytree0.65每棵树只用65%的特征列这相当于给特征空间做了随机剪枝在存在冗余特征时非常有用reg_alpha0.21和reg_lambda3.5说明给权重加了较强的L2约束有助于平滑输出降低过拟合。这套参数组合有一个明显倾向算法通过提高树的数量、降低学习率、增强正则化约束来换取更平滑的预测边界。这种组合在回归任务里非常吃香因为回归模型对目标值的微小抖动很敏感而正则化能够抑制训练集上的异常值带来的波动。4.3 LightGBM对比何时该换模型关于热搜里的lightgbm与xgboost的对比我在优化XGBoost时也顺手拿LightGBM做了个对照实验因为这两者在工程上经常被放一起比较。LightGBM最大的优势是训练速度它使用基于直方图的算法在特征分箱之后可以大幅降低计算复杂度尤其适合特征维度高、样本量大的场景。如果数据量达到几十万行以上同一组参数下LightGBM的训练时间通常只有XGBoost的1/3甚至更少。但速度不是免费午餐。LightGBM的直方图分箱会丢失一部分特征精度在小样本数据集上这种精度损失有时会抵消速度带来的收益。我的这组人工数据只有800行样本量实际测试中LightGBM默认参数的测试集RMSE约为1.91比XGBoost默认参数还差一些。所以我的结论是数据量大、特征多、工程上线时间紧的时候优先考虑LightGBM数据量不大、追求极致精度、希望有更成熟的正则化体系时XGBoost依然是很好的选择。SSA这套优化流程对两者都适用只需要把适应度函数里的模型类从XGBRegressor替换成LGBMRegressor即可。5. 常见问题与排坑实录5.1 搜索结果跑飞、收敛太慢怎么办我在跑SSAXGBoost时遇到的第一个问题是训练慢到怀疑人生。最初我设置的NP30、MAXITER50每个个体一次适应度评估要跑5折交叉验证总共评估30×501500次单次评估1.5秒总耗时接近40分钟。这对调一次参来说还能接受但如果需要反复调试效率就很低。解决方案有三个。第一减小种群规模和迭代次数NP18、MAXITER30通常能在10-15分钟内完成而且精度损失不大。第二在适应度函数里做“早停”设计如果连续3折的RMSE明显偏高直接跳过剩余折给该个体打一个较差分数。第三如果数据集很大先抽样出一份小的“代理数据集”用于搜索等参数选得差不多再用全量数据训练最终模型。另外搜索跑飞还体现在参数边界设置不当。比如reg_alpha如果上限设为100麻雀很容易在0.01到100之间乱跳扰动过大让算法无法聚焦。我的经验是把正则项参数的搜索边界设成1e-5到2.0左右实际最优值大概率不会超过10。5.2 交叉验证和进化搜索的边界要分清这是一个很隐蔽的坑。有人会为了节省时间把“5折交叉验证中的其中一折”拿来当作优化过程中的评估数据这是错误用法。优化搜索过程本身就是在利用数据寻找最优超参数如果评估数据同时又被用作搜索依据就相当于让算法“偷看答案”最终选出的参数必然过拟合。正确的做法是SSA优化全程只使用训练集内部的信息并且用5折交叉验证来获得无偏泛化估计。测试集从头到尾都不参与适应度评估只有最后模型训练完成后才用一次用来报告最终指标。这个“数据隔离”原则是调参自动化里的红线我见过太多人在这一步偷懒最后调出来的模型在训练集上很好一上测试集立刻崩掉。5.3 xgboost安装和API版本坑安装xgboost时最大的坑是版本不一致。新版xgboost的XGBRegressor接口来自xgboost.sklearn模块但很多老教程写的是直接from xgboost.sklearn import XGBRegressor在1.6版本中这种写法仍然兼容但在更早版本中可能有问题。建议统一写from xgboost import XGBRegressor这是目前最稳妥的导入方式。另外mean_squared_error(y_true, y_pred, squaredFalse)在sklearn 1.2版本中是合法的但在更早版本里没有squared参数返回的是MSE而不是RMSE。我写代码时总会用np.sqrt(mean_squared_error(...))来显式取RMSE避免版本差异导致误读。5.4 随机种子与可复现性智能优化算法自带随机性如果不固定种子每次跑出来的最优参数都有可能不同这会让实验结果变得很难复盘。我的做法是在脚本开头统一设置随机种子包括numpy、sklearn的交叉验证切分、以及XGBoost模型内部的random_state。这样同一个数据集、同一套代码跑三次结果完全一致。但要注意一点固定随机种子只是在代码层面保证可复现它不能解决模型本身的方差问题。所以报告中不要只贴“最好的一次结果”应该跑3-5次分别记录RMSE和R²的均值和标准差这样展示出来的结果才真实可信。6. 个人经验与后续扩展在实际项目中我习惯先跑一次默认参数作为基准然后让SSA跑30轮左右拿到结果后再手动微调一两个参数。为什么还要微调因为SSA搜索空间是连续取值的而XGBoost有些参数实际上是离散敏感的比如n_estimators从214变到220通常没什么差别但max_depth从5变到6可能变化明显。麻雀搜索会在几百次评估里不断试错最后选中的往往是一个“在交叉验证上表现稳健”的解但未必是“可解释性最好”的解这时候手动调整一下可以让模型更符合业务直觉。这个方案后续还可以往两个方向扩展。一个是把适应度函数从单指标改成多指标比如同时优化RMSE和模型训练时间用加权或者帕累托方法来寻找更合适的折中解。另一个是引入早停机制在fit的时候传入eval_set和early_stopping_rounds这样每棵树的迭代次数不依赖预设的n_estimators而是由验证集误差变化自动决定SSA优化的参数数量还可以进一步减少。我个人用这套流程的最深体会是调参本身不是目的理解参数之间的相互作用才是。麻雀算法不会告诉你为什么这组参数有效但它会让你亲眼看到不同超参数组合在交叉验证上的差异可以非常大。把这个优化框架搭好之后以后换数据集、换模型、换业务问题都只是改改适应度函数而已整个建模流程会轻松很多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进