【问题标题】:Using MultilabelBinarizer on test data with labels not in the training set对标签不在训练集中的测试数据使用 MultilabelBinarizer
【发布时间】:2015-10-08 19:56:05
【问题描述】:

鉴于这个简单的多标签分类示例(取自这个问题,use scikit-learn to classify into multiple categories

import numpy as np
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.svm import LinearSVC
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.multiclass import OneVsRestClassifier
from sklearn import preprocessing
from sklearn.metrics import accuracy_score

X_train = np.array(["new york is a hell of a town",
                "new york was originally dutch",
                "the big apple is great",
                "new york is also called the big apple",
                "nyc is nice",
                "people abbreviate new york city as nyc",
                "the capital of great britain is london",
                "london is in the uk",
                "london is in england",
                "london is in great britain",
                "it rains a lot in london",
                "london hosts the british museum",
                "new york is great and so is london",
                "i like london better than new york"])
y_train_text = [["new york"],["new york"],["new york"],["new york"],    ["new york"],
            ["new york"],["london"],["london"],["london"],["london"],
            ["london"],["london"],["new york","london"],["new york","london"]]

X_test = np.array(['nice day in nyc',
               'welcome to london',
               'london is rainy',
               'it is raining in britian',
               'it is raining in britian and the big apple',
               'it is raining in britian and nyc',
               'hello welcome to new york. enjoy it here and london too'])

y_test_text = [["new york"],["london"],["london"],["london"],["new york", "london"],["new york", "london"],["new york", "london"]]


lb = preprocessing.MultiLabelBinarizer()
Y = lb.fit_transform(y_train_text)
Y_test = lb.fit_transform(y_test_text)

classifier = Pipeline([
('vectorizer', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', OneVsRestClassifier(LinearSVC()))])

classifier.fit(X_train, Y)
predicted = classifier.predict(X_test)


print "Accuracy Score: ",accuracy_score(Y_test, predicted)

代码运行良好,并打印准确度分数,但是如果我将 y_test_text 更改为

y_test_text = [["new york"],["london"],["england"],["london"],["new york", "london"],["new york", "london"],["new york", "london"]]

我明白了

Traceback (most recent call last):
  File "/Users/scottstewart/Documents/scikittest/example.py", line 52, in <module>
     print "Accuracy Score: ",accuracy_score(Y_test, predicted)
  File "/Library/Python/2.7/site-packages/sklearn/metrics/classification.py", line 181, in accuracy_score
differing_labels = count_nonzero(y_true - y_pred, axis=1)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/sparse/compressed.py", line 393, in __sub__
raise ValueError("inconsistent shapes")
ValueError: inconsistent shapes

注意“england”标签的引入,它不在训练集中。如何使用多标签分类,以便如果引入“测试”标签,我仍然可以运行一些指标?或者这甚至可能吗?

编辑:感谢大家的回答,我想我的问题更多的是关于 scikit 二值化器如何工作或应该如何工作。鉴于我的简短示例代码,我也希望我将 y_test_text 更改为

y_test_text = [["new york"],["new york"],["new york"],["new york"],["new york"],["new york"],["new york"]]

它会起作用——我的意思是我们已经适应了那个标签,但在这种情况下我明白了

ValueError: Can't handle mix of binary and multilabel-indicator

【问题讨论】:

  • “一些指标”是什么意思?分类器无法预测它从未见过的标签。
  • 查看我编辑的答案,我想它涵盖了你所有的问题。
  • 谢谢乔吉!这就是我需要的。应该解决我更大的问题
  • 我很高兴,我可以帮助你。 :)

标签: python machine-learning scikit-learn


【解决方案1】:

如果你也可以在训练 y 集中“引入”新标签,如下所示:

import numpy as np
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.svm import LinearSVC
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.multiclass import OneVsRestClassifier
from sklearn import preprocessing
from sklearn.metrics import accuracy_score

X_train = np.array(["new york is a hell of a town",
                "new york was originally dutch",
                "the big apple is great",
                "new york is also called the big apple",
                "nyc is nice",
                "people abbreviate new york city as nyc",
                "the capital of great britain is london",
                "london is in the uk",
                "london is in england",
                "london is in great britain",
                "it rains a lot in london",
                "london hosts the british museum",
                "new york is great and so is london",
                "i like london better than new york"])
y_train_text = [["new york"],["new york"],["new york"],["new york"],    
                ["new york"],["new york"],["london"],["london"],         
                ["london"],["london"],["london"],["london"],
                ["new york","England"],["new york","london"]]

X_test = np.array(['nice day in nyc',
               'welcome to london',
               'london is rainy',
               'it is raining in britian',
               'it is raining in britian and the big apple',
               'it is raining in britian and nyc',
               'hello welcome to new york. enjoy it here and london too'])

y_test_text = [["new york"],["new york"],["new york"],["new york"],["new york"],["new york"],["new york"]]


lb = preprocessing.MultiLabelBinarizer(classes=("new york","london","England"))
Y = lb.fit_transform(y_train_text)
Y_test = lb.fit_transform(y_test_text)

print Y_test

classifier = Pipeline([
('vectorizer', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', OneVsRestClassifier(LinearSVC()))])

classifier.fit(X_train, Y)
predicted = classifier.predict(X_test)
print predicted

print "Accuracy Score: ",accuracy_score(Y_test, predicted)

输出:

Accuracy Score:  0.571428571429

关键部分是:

y_train_text = [["new york"],["new york"],["new york"],
                ["new york"],["new york"],["new york"],
                ["london"],["london"],["london"],["london"],
                ["london"],["london"],["new york","England"],
                ["new york","london"]]

我们也在其中插入了“英格兰”。 这是有道理的,因为如果他以前没有看到它,其他方式如何预测分类器的一些标签?所以我们以这种方式创建了一个三标签分类问题。

已编辑:

lb = preprocessing.MultiLabelBinarizer(classes=("new york","london","England"))

您必须将类作为 arg 传递给 MultiLabelBinarizer(),它适用于任何 y_test_text。

【讨论】:

  • 很好的答案。几个推荐。用于多标签分类的 sklearn.metrics.accuracy_score() 计算子集准确度(意思完全匹配)。但是,hamming_loss 计算预测的单个标签的准确性。 Consistent Multilabel Classification
【解决方案2】:

简而言之 - 这是一个不适定问题。分类假设所有标签都是预先知道的,binarizer 也是如此。适合所有标签,然后在您想要的任何子集上进行训练。

【讨论】:

  • 我认为不便之处在于,人们可能更喜欢 MultiLabelBinarizer 简单地忽略它没有看到的任何标签,而不是错误。与 CountVectorizer 的行为相比:如果在其 transform() 方法期间它看到了在 fit() 期间没有看到的标记,它将默默地忽略它们。这通常是您想要的,例如,使用与转换训练集相同的向量器转换测试集。同样,当您使用 MultiLabelBinarizer 转换您的测试标签时,您可能希望它默默地忽略您在训练中没有看到的任何内容。
  • 当您训练具有大量标签的多标签分类器时,更有可能出现此问题。尤其是当您在开发期间使用数据集的子集时。为了解决这个问题,我只是提前手动清理了标签。
  • 我在这里遇到了类似的问题:stats.stackexchange.com/questions/298046/…
【解决方案3】:

正如另一条评论中提到的,我个人希望二值化器在“转换”时忽略未见过的类。 如果测试样本呈现的特征与训练中使用的特征不同,则消耗二值化器结果的分类器可能反应不佳。

我解决了这个问题,只是从样本中删除了不可见的类。我认为比动态更改拟合的二值化器或(另一种选择)扩展它以允许忽略更安全。

list(map(lambda names: np.intersect1d(lb.classes_, names), y_test_text))

没有用你的实际代码运行

【讨论】:

    猜你喜欢
    • 2020-03-09
    • 2014-01-05
    • 2018-12-26
    • 2021-05-20
    • 1970-01-01
    • 2019-10-07
    • 2020-03-03
    • 1970-01-01
    • 2021-08-24
    相关资源
    最近更新 更多