使用 SKlearn 进行多标签分类 - 如何使用验证集?
Posted
技术标签:
【中文标题】使用 SKlearn 进行多标签分类 - 如何使用验证集?【英文标题】:Multi-label classification with SKlearn - How do you use a validation set? 【发布时间】:2021-08-25 11:06:32 【问题描述】:问题
我想在进行多标签分类时使用验证数据集提前停止,但似乎 sklearn 的 MultiOutputClassifier 不支持。您对解决方案有什么建议吗?
我做了什么
import numpy, sklearn
from sklearn.multioutput import MultiOutputClassifier
from xgboost import XGBClassifier
# Creating some multi-label data
X_train = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
X_valid = numpy.array([[2,3,7],[3,4,9],[7,8,7]])
Y_train = numpy.array([[1,0],[0,1],[1,1]])
Y_valid = numpy.array([[0,1],[1,1],[0,0]])
# Creating a multi-label xgboost
xgb = XGBClassifier(n_estimators=500, random_state=0, learning_rate=0.05, eval_metric='logloss')
xgb_ml = MultiOutputClassifier(xgb)
# Training the model
xgb_ml.fit(X_train, Y_train)
到这里为止,一切都按预期工作!
现在我想使用一个验证集来做一些提前停止。我使用与普通单标签 xgboost 相同的参数。
# Training model using an evaluation dataset
xgb_ml.fit(X_train, Y_train, eval_set=[(X_train, Y_train), (X_valid, Y_valid)], early_stopping_rounds=5)
>ValueError: y should be a 1d array, got an array of shape (3, 2) instead.
eval_set 参数似乎没有表明现在需要在多标签数据集的训练期间评估模型。这不支持吗?还是我做错了什么?
【问题讨论】:
它在抱怨y
的形状。 Y_train
和 Y_valid
在这里看起来像什么?
方法错误。 XGBClassifier
不支持开箱即用的多标签分类。我相信这就是为什么你一开始就把它包装在MultiOutputClassifier
中的原因。但是,您正在使用 eval_set
参数将多标签目标传递给 XGBClassifier
。那样是行不通的。
@afsharov 在文档中说:“可以将多标签分类支持添加到具有 MultiOutputClassifier 的任何分类器中”。这是因为该函数使用的方法是简单地制作所选分类器的 n_label 副本,然后为每个标签训练一个独立的模型。这也是为什么我希望它可以使用子参数,但显然支持是有限的,尽管 xgboost 是最流行的算法之一。这里是文档的链接:scikit-learn.org/stable/modules/…
这正是它不起作用的原因。 MultiOutputClassfier
只是分别为每个标签训练底层估计器的副本。因此,XGBClassifier
的每个副本当然仍然无法单独处理多标签输出。但是,您将目标数组作为 eval_set
中的 fit 参数直接传递给它们。
【参考方案1】:
@afsharov 在评论中指出了这个问题。 sklearn
对 fit_params
一无所知,它只是将它们传递给各个单输出模型。
MultiOutputClassifier
做的不多,所以简单地循环遍历目标,拟合 xgboost 模型并将它们保存到列表中并不是什么大问题。主要打击似乎是并行化的损失,但您也可以自己做。
如果您真的希望所有内容都包含在一个类中,我认为从MultiOutputClassifier
派生并覆盖fit
方法就足够了。您将复制大部分原始 fit 方法(classes_
属性设置和大部分父类 _MultiOutputEstimator
的 fit
方法),但将 eval_set
第二个元素分解为它们的列并将它们压缩在一起平行拟合。大致如下:
# current code
fit_params_validated = _check_fit_params(X, fit_params)
self.estimators_ = Parallel(n_jobs=self.n_jobs)(
delayed(_fit_estimator)(
self.estimator, X, y[:, i], sample_weight,
**fit_params_validated)
for i in range(y.shape[1]))
(source) 到
fit_params_validated = _check_fit_params(X, fit_params)
eval_set = fit_params_validated.pop("eval_set", [(X, y)])
eval_set_sliced = [(eval_set_i[0], eval_set_i[1][:, i]) for eval_set_i in eval_set]
self.estimators_ = Parallel(n_jobs=self.n_jobs)(
delayed(_fit_estimator)(
self.estimator, X, y[:, i], sample_weight,
eval_set=eval_set_sliced[i],
**fit_params_validated)
for i in range(y.shape[1]))
【讨论】:
感谢 Ben,看来 MultiOutputClassifier 并不值得,而且我最好自己构建。当我阅读文档时,我认为这将是一个方便的包装器,但事实证明,使用更复杂的算法更麻烦。这对于不依赖提前停止的模型来说很好。以上是关于使用 SKlearn 进行多标签分类 - 如何使用验证集?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 sklearn.metrics 计算多标签分类任务的微观/宏观度量?
Sklearn Linear SVM 无法在多标签分类中进行训练