Python 使用scikit学习如何分类为多个类别

Python 使用scikit学习如何分类为多个类别,python,classification,scikit-learn,Python,Classification,Scikit Learn,我正在尝试使用scikit learn的监督学习方法将文本片段分类为一个或多个类别。我尝试的所有算法的predict函数只返回一个匹配项 例如,我有一段文字: "Theaters in New York compared to those in London" 我还训练了算法,为我输入的每个文本片段选择一个位置 在上面的示例中,我希望它返回newyork和London,但它只返回newyork 是否可以使用scikit learn返回多个结果?或者以次高概率返回标签 谢谢你的帮助 ---更新

我正在尝试使用scikit learn的监督学习方法将文本片段分类为一个或多个类别。我尝试的所有算法的predict函数只返回一个匹配项

例如,我有一段文字:

"Theaters in New York compared to those in London"
我还训练了算法,为我输入的每个文本片段选择一个位置

在上面的示例中,我希望它返回
newyork
London
,但它只返回
newyork

是否可以使用scikit learn返回多个结果?或者以次高概率返回标签

谢谢你的帮助

---更新

我试着使用
OneVsRestClassifier
,但我仍然只能从每段文本中获得一个选项。下面是我正在使用的示例代码

y_train = ('New York','London')


train_set = ("new york nyc big apple", "london uk great britain")
vocab = {'new york' :0,'nyc':1,'big apple':2,'london' : 3, 'uk': 4, 'great britain' : 5}
count = CountVectorizer(analyzer=WordNGramAnalyzer(min_n=1, max_n=2),vocabulary=vocab)
test_set = ('nice day in nyc','london town','hello welcome to the big apple. enjoy it here and london too')

X_vectorized = count.transform(train_set).todense()
smatrix2  = count.transform(test_set).todense()


base_clf = MultinomialNB(alpha=1)

clf = OneVsRestClassifier(base_clf).fit(X_vectorized, y_train)
Y_pred = clf.predict(smatrix2)
print Y_pred

结果:[“纽约”“伦敦”“伦敦”]

您需要的是多标签分类。我可以做到这一点。请参见此处:

我不确定你的例子中出了什么问题,我的sklearn版本显然没有WordNGramAnalyzer。也许这是一个使用更多训练示例或尝试不同分类器的问题?但是请注意,多标签分类器希望目标是元组列表/标签列表

以下是我的作品:

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

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 = [[0],[0],[0],[0],[0],[0],[1],[1],[1],[1],[1],[1],[0,1],[0,1]]
X_test = np.array(['nice day in nyc',
                   'welcome to london',
                   'hello welcome to new york. enjoy it here and london too'])   
target_names = ['New York', 'London']

classifier = Pipeline([
    ('vectorizer', CountVectorizer(min_n=1,max_n=2)),
    ('tfidf', TfidfTransformer()),
    ('clf', OneVsRestClassifier(LinearSVC()))])
classifier.fit(X_train, y_train)
predicted = classifier.predict(X_test)
for item, labels in zip(X_test, predicted):
    print '%s => %s' % (item, ', '.join(target_names[x] for x in labels))
对我来说,这会产生以下输出:

nice day in nyc => New York
welcome to london => London
hello welcome to new york. enjoy it here and london too => New York, London

希望这有帮助。

我也遇到了这个问题,我的问题是我的y_序列是一个字符串序列,而不是一个字符串序列。显然,OneVsRestClassifier将根据输入标签格式决定是否使用多类还是多标签。因此,改变:

y_train = ('New York','London')


显然,这将在将来消失,因为所有标签都是相同的:

编辑:根据建议使用MultiLabelBinarizer为Python 3更新scikit learn 0.18.1

我也一直在做这方面的工作,并对mwv的优秀答案做了一点改进,这可能是有用的。它将文本标签作为输入,而不是二进制标签,并使用MultiLabelBinarizer对其进行编码

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.preprocessing import MultiLabelBinarizer

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'])
target_names = ['New York', 'London']

mlb = MultiLabelBinarizer()
Y = mlb.fit_transform(y_train_text)

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

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

for item, labels in zip(X_test, all_labels):
    print('{0} => {1}'.format(item, ', '.join(labels)))
这为我提供了以下输出:

nice day in nyc => new york
welcome to london => london
london is rainy => london
it is raining in britian => london
it is raining in britian and the big apple => new york
it is raining in britian and nyc => london, new york
hello welcome to new york. enjoy it here and london too => london, new york

更改此行以使其在新版本的python中工作

# lb = preprocessing.LabelBinarizer()
lb = preprocessing.MultiLabelBinarizer()

以下是几个多重分类示例:-

例1:-

import numpy as np
from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()

arr2d = np.array([1, 2, 3,4,5,6,7,8,9,10,11,12,13,14,1])
transfomed_label = encoder.fit_transform(arr2d)
print(transfomed_label)
输出为

[[1 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 1 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 1 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 1 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 1 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 1 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 1 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 1 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 1 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 1 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 1 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 1 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 1]
 [1 0 0 0 0 0 0 0 0 0 0 0 0 0]]
例2:-

import numpy as np
from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()

arr2d = np.array(['Leopard','Lion','Tiger', 'Lion'])
transfomed_label = encoder.fit_transform(arr2d)
print(transfomed_label)
输出为

[[1 0 0]
 [0 1 0]
 [0 0 1]
 [0 1 0]]

我试着删除最后两个结合了城市名称的培训示例,结果得到:你好,欢迎来到纽约。在这里和伦敦享受它=>纽约它不再返回两个标签。对我来说,如果我训练这两个城市的组合,它只会返回两个标签。我错过什么了吗?再次感谢您的帮助这只是一个玩具数据集,我不会从中得出太多的结论。你在真实数据上尝试过这个过程吗?@CodeMonkeyB:你真的应该接受这个答案,从编程的角度来看,它是正确的。它在实践中是否有效取决于您的数据,而不是代码。是否有其他人对
min\u n
max\u n
有问题。我需要将它们更改为
ngram_range=(1,2)
以进行工作。它给出了以下错误:ValueError:您似乎正在使用传统的多标签数据表示。序列序列不再受支持;请改用二进制数组或稀疏矩阵。
labelBinarizer
已过时。使用
lb=preprocessing.multi-labelbinarizer()
insteadIt不提供英国,因为唯一的输出标签是
New York
London
。根据一对一,除了sklearn.svm.SVC之外,所有线性模型都支持所有标签,而且多标签还支持:决策树、随机森林、最近邻、,因此,我不会将LinearSVC()用于这种类型的任务(也称为我假设您要使用的多标签分类),仅供参考@mindstorm提到的所有分类与scikit学习类“OneVsRestClassifier”(注意“Rest”而不是“All”)相对应。正如@mindstorm所提到的,文档中确实提到:“一对所有:除了sklearn.svm.SVC之外的所有线性模型”。然而,显示了一个具有以下行的多标签示例
classif=OneVsRestClassifier(SVC(kernel='linear'))
。困惑的
[[1 0 0]
 [0 1 0]
 [0 0 1]
 [0 1 0]]