Вопрос по python – Используйте Scikit-Learn для классификации на несколько категорий

72

Я пытаюсь использовать один из контролируемых методов обучения scikit-learn для классификации фрагментов текста по одной или нескольким категориям. Функция предсказания всех алгоритмов, которые я попробовал, просто возвращает одно совпадение.

Например, у меня есть кусок текста:

"Theaters in New York compared to those in London"

И я тренировал алгоритм, чтобы выбрать место для каждого фрагмента текста, который я кормлю.

В приведенном выше примере я бы хотел, чтобы он вернулсяNew York а такжеLondon, но это только возвращаетNew York.

Можно ли использовать 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

Результат: ['New York'; & APOS; Лондон & APOS; & APOS; London & APOS;]

Ваш Ответ

5   ответов
1

Несколько мульти классификационных примеров приведены ниже:

Пример 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]]
6

Измените эту строку, чтобы она работала в новых версиях python

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

То, что вы хотите, называется классификацией нескольких меток. Scikits-Learn может сделать это. Посмотреть здесь:http://scikit-learn.org/dev/modules/multiclass.html.

Я не уверен, что не так в вашем примере, моя версия 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

Надеюсь это поможет.

Error: User Rate Limit Exceeded
Я попытался удалить последние два примера обучения, которые объединяют названия городов, и я получаю: привет, добро пожаловать в Нью-Йорк. наслаждайтесь здесь и в Лондоне тоже = & gt; Нью-Йорк больше не возвращает два ярлыка. Для меня возвращаются только две метки, если я тренирую комбинации двух городов. Я что-то пропустил? Еще раз спасибо за вашу помощь CodeMonkeyB
Error: User Rate Limit Exceeded
Кто-нибудь еще получает проблемы сmin_n а такжеmax_n, Мне нужно изменить их наngram_range=(1,2) работать
Это просто набор игрушечных данных, я бы не стал делать из этого слишком много выводов. Вы пробовали эту процедуру на ваших реальных данных?
51

РЕДАКТИРОВАТЬ: Обновлено для Python 3, scikit-learn 0.18.1 с использованием MultiLabelBinarizer, как предложено.

Я также работал над этим и внес небольшое улучшение в превосходный ответ 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
labelBinarizerError: User Rate Limit Exceededlb = preprocessing.MultiLabelBinarizer()Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededNew YorkError: User Rate Limit ExceededLondon.
Error: User Rate Limit ExceededThis scikit-learn help pageError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededscikit-learnError: User Rate Limit Exceeded
6

Я просто столкнулся с этим, и проблема для меня заключалась в том, что мой y_Train был последовательностью строк, а не последовательностью последовательностей строк. По-видимому, OneVsRestClassifier на основе формата входной метки примет решение о том, использовать ли мультикласс по сравнению с мультиметкой. Так что поменяйте:

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

в

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

По всей видимости, это исчезнет в будущем, поскольку разрывы всех меток одинаковы:https://github.com/scikit-learn/scikit-learn/pull/1987

Похожие вопросы