You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决XGBoost 1.6.2中的“早停需至少1个验证数据集”断言错误

解决BayesSearchCV结合XGBoost设置early_stopping_rounds的报错问题

错误根源

XGBoost的early_stopping_rounds参数要求训练时必须传入至少一组验证集,但默认情况下BayesSearchCV的交叉验证流程不会自动将拆分出的验证折传递给XGBoost的fit方法,触发断言错误:AssertionError: Must have at least 1 validation dataset for early stopping.

可行解决方案

方案1:自定义XGBClassifier实现内部验证集拆分

创建继承自XGBClassifier的子类,重写fit方法,自动从当前训练数据中拆分验证集供early stopping使用,贴合交叉验证流程:

import numpy as np
from sklearn.model_selection import train_test_split
from xgboost import XGBClassifier

class XGBEarlyStoppingClassifier(XGBClassifier):
    def fit(self, X, y, **fit_params):
        # 按8:2比例拆分训练/验证集,保持类别分布一致
        X_train, X_val, y_train, y_val = train_test_split(
            X, y, test_size=0.2, random_state=42, stratify=y
        )
        # 调用父类fit方法,传入验证集和early stopping参数
        super().fit(
            X_train, y_train,
            eval_set=[(X_val, y_val)],
            early_stopping_rounds=10,
            verbose=False,
            **fit_params
        )
        return self

替换原代码中的XGBClassifier为自定义类,移除初始化时的early_stopping_rounds参数:

from skopt import BayesSearchCV  
from sklearn.model_selection import StratifiedKFold
import pandas as pd
import numpy as np

bayes_cv_tuner = BayesSearchCV(     
    estimator = XGBEarlyStoppingClassifier(         
        n_jobs = 8,         
        objective = 'binary:logistic',         
        eval_metric = 'auc',         
        silent=1,         
        tree_method='approx'
    ),     
    search_spaces = {         
        'learning_rate': (0.001, 0.005),         
        'min_child_weight': (150, 500),         
        'max_depth': (2, 4),         
        'max_delta_step': (1, 10),         
        'subsample': (0.5, .9),         
        'colsample_bytree': (0.6, 0.8),         
        'colsample_bylevel': (0.6, 0.9),         
        'reg_lambda':(100,500),         
        'reg_alpha': (0.005,.05),         
        'gamma':  (2.5,10),         
        'n_estimators': (25, 100),         
        'scale_pos_weight': (1, 1000)     },         
    scoring = 'roc_auc',     
    cv = StratifiedKFold(         
        n_splits=5,         
        shuffle=True,         
        random_state=42     ),     
    n_jobs = 8,     
    n_iter = 80,        
    refit = True,     
    random_state = 42 )  

def status_print(optim_result):     
    """Status callback during bayesian hyperparameter search"""          
    all_models = pd.DataFrame(bayes_cv_tuner.cv_results_)              
    print('Model #{}\nBest ROC-AUC: {}\nBest params: {}\n'.format(         
        len(all_models),         
        np.round(bayes_cv_tuner.best_score_, 4),         
        bayes_cv_tuner.best_params_     ))          
    clf_name = bayes_cv_tuner.estimator.__class__.__name__     
    all_models.to_csv(clf_name+"_cv_results.csv")

# 正常调用fit即可
result = bayes_cv_tuner.fit(data_train.iloc[:,1:-1], data_train.iloc[:,-1], callback=status_print)

方案2:通过fit_params传递外部验证集

提前拆分独立的训练集和验证集,在调用fit时通过fit_params把验证集传给XGBoost,适合需要固定验证集监控性能的场景:

# 提前拆分数据
X = data_train.iloc[:,1:-1]
y = data_train.iloc[:,-1]
X_train, X_val, y_train, y_val = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)

# 初始化BayesSearchCV时,estimator不设置early_stopping_rounds
bayes_cv_tuner = BayesSearchCV(     
    estimator = XGBClassifier(         
        n_jobs = 8,         
        objective = 'binary:logistic',         
        eval_metric = 'auc',         
        silent=1,         
        tree_method='approx'
    ),     
    # 其余参数与原代码一致
    search_spaces = {         
        'learning_rate': (0.001, 0.005),         
        'min_child_weight': (150, 500),         
        'max_depth': (2, 4),         
        'max_delta_step': (1, 10),         
        'subsample': (0.5, .9),         
        'colsample_bytree': (0.6, 0.8),         
        'colsample_bylevel': (0.6, 0.9),         
        'reg_lambda':(100,500),         
        'reg_alpha': (0.005,.05),         
        'gamma':  (2.5,10),         
        'n_estimators': (25, 100),         
        'scale_pos_weight': (1, 1000)     },         
    scoring = 'roc_auc',     
    cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42),     
    n_jobs = 8,     
    n_iter = 80,        
    refit = True,     
    random_state = 42 )  

# 调用fit时传递验证集和early stopping参数
result = bayes_cv_tuner.fit(
    X_train, y_train,
    callback=status_print,
    fit_params={
        "early_stopping_rounds": 10,
        "eval_set": [(X_val, y_val)],
        "verbose": False
    }
)

关键注意事项

  • 自定义类拆分验证集时,务必使用stratify=y保证类别分布一致,避免样本偏差。
  • 不要在XGBClassifier初始化阶段设置early_stopping_rounds,必须搭配对应的eval_set一起传入fit方法。
  • 方案1的逻辑更贴合交叉验证流程,每个fold内部独立做early stopping,能有效避免数据泄露;方案2适合需要固定验证集监控模型性能的场景。

内容的提问来源于stack exchange,提问作者SHESADEV SHA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:24:55