HpBandSterSearchCV(hpbandster-sklearn)迭代后期为何返回NaN分数?
在使用hpbandster-sklearn包对XGBoost模型进行Hyperband超参数调优时,出现异常现象:首轮迭代能得到有效分数的参数,后续使用更多数据迭代时却返回NaN分数,且其他条件未发生变化。示例代码运行后,首轮就存在大量NaN分数,进入后续迭代的参数全部返回NaN,导致最优参数选取近乎随机。调整交叉折数、随机状态、评估指标等设置后,问题仍普遍存在,甚至在更大数据集上首轮也会出现大量NaN。
复现代码
from sklearn import datasets from xgboost import XGBClassifier from hpbandster_sklearn import HpBandSterSearchCV import ConfigSpace as CS from ConfigSpace import ConfigurationSpace, Integer, Float import pandas as pd X, y = datasets.load_breast_cancer(return_X_y = True, as_frame = True) xgb = XGBClassifier( eval_metric = ['map','logloss','auc'], objective = 'binary:logistic', n_jobs = -1, verbosity = 0 ) params = ConfigurationSpace(seed=16069) params.add_hyperparameter(Float('learning_rate', (0.1, 0.3), log=True)) params.add_hyperparameter(Integer('n_estimators', (100, 200))) search = HpBandSterSearchCV(xgb, params, optimizer = 'hyperband', random_state = 65, n_jobs = -1, n_iter = 3, cv = 5, verbose = 0, resource_name = 'n_samples', return_train_score = True, scoring = 'neg_log_loss', resource_type = float, min_budget = 0.11) search.fit(X, y) pd.DataFrame(search.cv_results_)
运行上述代码后,cv_results_表格中会出现大量NaN分数,尤其是后续迭代的参数结果全为NaN。
问题成因与误区分析
1. resource_name参数误用
HpBandSter的resource_name用于指定模型训练时可逐步递增的资源参数,比如XGBoost的n_estimators(树的数量),而非训练样本量。当你设置resource_name='n_samples'时,HpBandSter会尝试修改XGBoost模型不存在的n_samples参数,导致训练逻辑混乱,最终计算分数时返回NaN。
2. 极小样本量引发的极端数据分布
设置min_budget=0.11意味着仅用11%的样本训练模型,此时交叉验证的部分折可能出现极端类别不平衡(比如某折只有几个样本且全为同一类别)。计算neg_log_loss时,若模型预测概率为0或1,会触发log(0)的无意义计算,直接返回NaN。后续迭代增加样本量时,若仍遇到此类极端折,问题会持续存在。
3. 评估指标与训练逻辑的潜在冲突
XGBoost设置了多评估指标eval_metric=['map','logloss','auc'],而HpBandSter使用scoring='neg_log_loss'作为最终评分。虽然两者本身不冲突,但当模型在极小样本上训练时,容易出现极端预测值,既会触发XGBoost内部eval_metric的计算异常,也会导致sklearn的neg_log_loss返回NaN。
解决建议
- 修正
resource_name参数:将其改为XGBoost支持的可增量资源,比如'n_estimators',让Hyperband逐步增加树的数量,符合模型训练逻辑。同时调整min_budget和max_budget为合理的树数量范围,比如min_budget=50,max_budget=200。 - 避免极端样本量:不要使用过小的
min_budget比例,确保每折交叉验证的样本量足够维持基本的类别分布。 - 使用分层交叉验证:将
cv设置为StratifiedKFold(n_splits=5),强制每折数据的类别分布与整体一致,避免单一类别折的出现。 - 添加防NaN处理:在XGBoost中设置
use_label_encoder=False(避免旧版本的编码问题),同时可以在模型参数中加入early_stopping_rounds=10,防止模型在极小样本上过拟合产生极端预测值。
内容的提问来源于stack exchange,提问作者VanDerGraaf

