如何修改sklearn层级分类器适配XGBoost?解决属性错误
修复XGBoost与sklearn-hierarchical-classification层级分类适配问题
问题描述
使用已归档的sklearn-hierarchical-classification库实现层级分类时,基于RandomForestClassifier的基础分类器可正常运行,但替换为XGBClassifier时触发如下错误:
AttributeError: 'bool' object has no attribute 'all'
错误根源在于XGBoost的fit方法中对类别一致性的校验逻辑:
if ( self.classes_.shape != expected_classes.shape or not (self.classes_ == expected_classes).all() ): raise ValueError(...)
当层级分类的内部节点使用字符串类别(如['A', 'B'])时,self.classes_ == expected_classes返回单个布尔值而非数组,导致调用.all()方法失败——XGBoost默认期望接收整数编码的类别标签。
修复方案
方案1:包装XGBClassifier(无需修改原库代码)
创建一个包装类,自动处理字符串标签与整数编码的转换,无需改动原层级分类库的代码:
from sklearn.preprocessing import LabelEncoder from xgboost import XGBClassifier class XGBClassifierWrapper: def __init__(self, **kwargs): self.xgb = XGBClassifier(**kwargs) self.le = LabelEncoder() def fit(self, X, y): # 将字符串标签转换为整数编码 y_encoded = self.le.fit_transform(y) self.xgb.fit(X, y_encoded) return self def predict(self, X): # 将整数预测结果转回字符串标签 preds = self.xgb.predict(X) return self.le.inverse_transform(preds) # 代理XGBClassifier的其他属性和方法 def __getattr__(self, name): return getattr(self.xgb, name)
使用该包装类作为基础分类器:
# 替换原XGBClassifier为包装类 base2 = XGBClassifierWrapper() clf = HierarchicalClassifier( base_estimator=base2, class_hierarchy=class_hierarchy, ) # 后续训练、预测代码保持不变 X, y = make_digits_dataset(targets=[1, 7, 3, 8, 9], as_str=False) y = y.astype(str) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, ) clf.fit(X_train, y_train) y_pred = clf.predict(X_test) with multi_labeled(y_test, y_pred, clf.graph_) as (y_test_, y_pred_, graph_): h_fbeta = h_fbeta_score(y_test_, y_pred_, graph_) print("h_fbeta_score: ", h_fbeta)
方案2:修改原层级分类库代码
如果允许修改sklearn_hierarchical_classification/classifier.py,可以直接修改_train_local_classifier和_recursive_predict方法,添加标签编码逻辑:
- 修改
_train_local_classifier方法:
# 在文件顶部导入LabelEncoder from sklearn.preprocessing import LabelEncoder # 找到_train_local_classifier方法,修改为: def _train_local_classifier(self, X, y, node_id): # ... 保留原方法中获取X_和y_的代码 ... # 添加标签编码步骤 le = LabelEncoder() y_encoded = le.fit_transform(y_) clf.fit(X=X_, y=y_encoded) # 保存分类器和编码器的元组 self.local_classifiers_[node_id] = (clf, le)
- 修改
_recursive_predict方法:
找到方法中调用local_classifier.predict(X)的部分,修改为:
# 原代码: # y_pred_node = self.local_classifiers_[node_id].predict(X) # 修改为: clf, le = self.local_classifiers_[node_id] y_pred_node = le.inverse_transform(clf.predict(X))
修改完成后,直接使用原XGBClassifier即可正常运行。
验证结果
修复后,层级分类器可正常训练并输出评估指标,例如:
h_fbeta_score: 0.972...
内容的提问来源于stack exchange,提问作者arilwan
相关产品推荐
相关产品推荐

