Pipeline中XGBoostClassifier多分类任务class_weight的正确使用方法
如何在Pipeline中为XGBoost多分类任务配置类别权重
报错原因
你看到的警告是两个错误用法共同导致的:
- XGBoost官方原生的
XGBClassifier没有内置class_weight参数,该参数是Scikit-learn部分模型的专属入参,直接传入XGBoost构造函数会被识别为无效参数。 sample_weight是模型fit()方法的入参,不属于模型初始化阶段的配置参数,写在构造函数中无法被XGBoost核心逻辑识别。
正确实现方案
方案1:通过Pipeline的fit_params传参(最简便)
Pipeline的fit方法支持传入步骤名__参数名格式的参数,给指定步骤的fit方法传值,你只需要提前算好样本权重,在调用fit时传入即可:
import numpy as np from sklearn.utils import class_weight from sklearn.pipeline import Pipeline from xgboost import XGBClassifier # 1. 计算训练集每个样本对应的权重 classes_weights = class_weight.compute_class_weight( 'balanced', classes=np.unique(y_train), y=y_train ) sample_weights = np.array([classes_weights[y] for y in y_train]) # 2. 构造Pipeline,XGB构造函数不需要传class_weight、sample_weight参数 pipe = Pipeline([ # 此处补充你的预处理步骤,例如标准化、特征选择等 ('clf', XGBClassifier(n_jobs=-1, objective='multi:softprob')) ]) # 3. 调用fit时通过双下划线格式传入样本权重 pipe.fit(X_train, y_train, clf__sample_weight=sample_weights)
如果配合GridSearchCV等交叉验证工具使用,同样可以把该参数传入搜索类的fit方法:
from sklearn.model_selection import GridSearchCV params = {'clf__max_depth': [3,5,7]} grid = GridSearchCV(pipe, params, cv=5) grid.fit(X_train, y_train, clf__sample_weight=sample_weights)
方案2:自定义封装支持class_weight的XGB类(高复用性)
如果你希望和Scikit-learn其他模型一样,直接传入class_weight='balanced'即可自动处理权重,可以自定义一个继承XGBClassifier的扩展类:
from xgboost import XGBClassifier from sklearn.utils.class_weight import compute_class_weight import numpy as np class XGBClassifierWeighted(XGBClassifier): def __init__(self, class_weight=None, **kwargs): self.class_weight = class_weight super().__init__(**kwargs) def fit(self, X, y, sample_weight=None, **kwargs): if self.class_weight == 'balanced' and sample_weight is None: # 自动基于当前传入的训练集标签计算权重 classes = np.unique(y) classes_weights = compute_class_weight('balanced', classes=classes, y=y) sample_weight = np.array([classes_weights[np.where(classes == label)[0][0]] for label in y]) return super().fit(X, y, sample_weight=sample_weight, **kwargs)
使用时直接在Pipeline中初始化该自定义类即可,不需要手动计算权重:
pipe = Pipeline([ # 预处理步骤 ('clf', XGBClassifierWeighted(class_weight='balanced', n_jobs=-1, objective='multi:softprob')) ]) pipe.fit(X_train, y_train)
注意事项
如果使用K折交叉验证,不要基于全量数据集的标签计算样本权重,应该基于每个训练折的标签单独计算,避免数据泄露,这种场景更推荐使用自定义封装类,会自动在每个fit阶段基于当前传入的y计算权重。
内容的提问来源于stack exchange,提问作者Deshwal
相关产品推荐
相关产品推荐

