给出这个简单的多标签分类示例(取自这个问题,使用scikit-learn将其分为多个类别)
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
你可以,如果你在训练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"]]
我们也插入了"England"。这是有道理的,因为如果分类器之前没有看到某个标签怎么能预测它呢?所以我们用这种方法创建了一个三标签分类问题。
编辑:
lb = preprocessing.MultiLabelBinarizer(classes=("new york","london","England"))
您必须将类作为arg传递给MultiLabelBinarizer()
,它将与任何y_test_text一起工作。
简而言之,这是一个不适定问题。分类假设所有标签都是事先已知的, binarizer也是如此。在所有标签上匹配它,然后在你想要的任何子集上训练。
正如在另一个评论中提到的,我个人希望二进制化器在"转换"时忽略未看到的类。如果测试样本呈现的特征与训练中使用的特征不同,则消耗二值化器结果的分类器可能反应不佳。
我解决了这个问题,只是从样本中删除了未见的类。我认为这是一种比动态更改拟合的二值化器或(另一种选择)扩展它以允许忽略更安全的方法。
list(map(lambda names: np.intersect1d(lb.classes_, names), y_test_text))
没有在实际代码中运行