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

如何修改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方法,添加标签编码逻辑:

  1. 修改_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)
  1. 修改_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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:07:07