Python 在多标签分类中使用样本权重
当我使用线性SVM在scikit learn中处理分类问题时,我可以对每个训练样本应用自定义权重,如下所示:Python 在多标签分类中使用样本权重,python,scikit-learn,classification,Python,Scikit Learn,Classification,当我使用线性SVM在scikit learn中处理分类问题时,我可以对每个训练样本应用自定义权重,如下所示: from sklearn.linear_model import SGDClassifier X = [[0.0, 0.0], [1.0, 1.0]] y = [0, 1] sample_weight = [1.0, 0.5] clf = SGDClassifier(loss="hinge") clf.fit(X, y, sample_weight=sample_weight) 现在
from sklearn.linear_model import SGDClassifier
X = [[0.0, 0.0], [1.0, 1.0]]
y = [0, 1]
sample_weight = [1.0, 0.5]
clf = SGDClassifier(loss="hinge")
clf.fit(X, y, sample_weight=sample_weight)
现在,当我有一个多标签分类任务时,我需要转换标签,sgdclassizer
必须包装在一个元估计器中,如OneVsRestClassifier
:
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import SGDClassifier
X = [[0.0, 0.0], [1.0, 1.0], [1.0, 0.0]]
y = [[0], [1], [0, 1]]
y_mlb = MultiLabelBinarizer().fit_transform(y)
sample_weight = [1.0, 0.5, 0.8]
clf = OneVsRestClassifier(SGDClassifier(loss="hinge"))
clf.fit(X, y_mlb) # unable to pass `sample_weight`
但是,除了
X
和y
之外,OneVsRestClassifier
不允许我向fit
方法传递任何参数,因此我无法像以前那样应用样本权重。在这种情况下,我如何应用自己的样本权重?相反,请尝试将OneVsRestClassifier子类化,以更改fit方法以允许传递样本权重。
您需要更改其中使用的fit()和_fit_binary()方法
请尝试编辑以下内容:
import warnings
import numpy as np
from sklearn.externals.joblib import Parallel, delayed
from sklearn.base import clone
from sklearn.multiclass import _ConstantPredictor, OneVsRestClassifier
from sklearn.preprocessing import LabelBinarizer, MultiLabelBinarizer
from sklearn.linear_model import SGDClassifier
def _fit_binary_new(estimator, X, y, sample_weight, classes=None):
unique_y = np.unique(y)
if len(unique_y) == 1:
if classes is not None:
if y[0] == -1:
c = 0
else:
c = y[0]
warnings.warn("Label %s is present in all training examples." %
str(classes[c]))
estimator = _ConstantPredictor().fit(X, unique_y)
else:
estimator = clone(estimator)
# Only this changed
estimator.fit(X, y, sample_weight=sample_weight)
return estimator
class OneVsRestClassifierNew(OneVsRestClassifier):
def fit(self, X, y, sample_weight=None):
self.label_binarizer_ = LabelBinarizer(sparse_output=True)
Y = self.label_binarizer_.fit_transform(y)
Y = Y.tocsc()
self.classes_ = self.label_binarizer_.classes_
columns = (col.toarray().ravel() for col in Y.T)
self.estimators_ = Parallel(n_jobs=self.n_jobs)(delayed(_fit_binary_new)(
self.estimator, X, column, sample_weight, classes=[
"not %s" % self.label_binarizer_.classes_[i],
self.label_binarizer_.classes_[i]])
for i, column in enumerate(columns))
return self
X = [[0.0, 0.0], [1.0, 1.0], [1.0, 0.0]]
y = [[0], [1], [0, 1]]
y_mlb = MultiLabelBinarizer().fit_transform(y)
sample_weight = [1.0, 0.5, 0.8]
clf = OneVsRestClassifierNew(SGDClassifier(loss="hinge"))
clf.fit(X, y_mlb, sample_weight=sample_weight)
clf.predict(X)
# Output: array([[1, 0],
# [0, 1],
# [1, 1]])
注意:这只适用于那些在fit()方法中定义了sample\u weight的分类器,因为我不检查
\u fit\u binary\u new()中是否存在
我试图用一个技巧解决这个问题:用一个自定义实现替换sgdclassizer
实例的fit
方法,该实现获取对我的样本权重列表的引用,但是:结果是OneVsRestClassifier
克隆了估计器。当然,不是使用标准的python工具,而是使用从get_params
方法检索的参数实例化同一类的新估计器。因此,猴子补丁没有被保留,我又回到了原点……因此现在我可以将sgdclassizer
子类化,添加样本权重作为实例参数,修补get_params
方法,修补fit
方法以使用类中存储的样本权重。。。这是可怕的,这似乎工作,但我可以看到它将如何爆炸,一旦sklearn开发人员决定触摸其中一个功能。也许我应该为此提交一份bug报告(或功能请求)。无论如何,谢谢你的回答。@Klamann可能是因为OneVsRestClassifier设计用于所有不适合样本权重的估计器()。无论如何,我试图搜索此请求的现有问题,但找不到。请随意补充。另外,请接受答案,如果它的工作和帮助。我已经为此提交了一份报告。我知道OneVsRestClassifier应该能够与其他估计器一起工作,因此显而易见的解决方案是将任意Kwarg传递给底层估计器。我会把这件事留一段时间,也许有人会想出一个不那么麻烦的解决办法。