webentwicklung-frage-antwort-db.com.de

Verwenden Sie scikit-learn, um in mehrere Kategorien einzuordnen

Ich versuche, eine von scikit-learns überwachte Lernmethode zu verwenden, um Textteile in eine oder mehrere Kategorien zu klassifizieren. Die Vorhersagefunktion aller Algorithmen, die ich ausprobiert habe, liefert nur eine Übereinstimmung.

Zum Beispiel habe ich einen Text:

"Theaters in New York compared to those in London"

Und ich habe den Algorithmus trainiert, um einen Platz für jedes Text-Snippet auszuwählen, das ich füttere.

Im obigen Beispiel würde ich möchten, dass es New York und London zurückgibt, aber es gibt nur New York zurück.

Kann ich mit scikit-learn mehrere Ergebnisse zurückgeben? Oder sogar das Etikett mit der nächsthöchsten Wahrscheinlichkeit zurückschicken? 

Danke für Ihre Hilfe.

---Aktualisieren 

Ich habe versucht, OneVsRestClassifier zu verwenden, bekomme aber immer nur eine Option pro Text zurück. Unten ist der Beispielcode, den ich verwende

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

Ergebnis: ['New York' 'London' 'London']

69
CodeMonkeyB

Was Sie wollen, wird als Multi-Label-Klassifizierung bezeichnet. Scikits-learn kann das. Siehe hier: http://scikit-learn.org/dev/modules/multiclass.html .

Ich bin nicht sicher, was in Ihrem Beispiel falsch läuft, meine Version von sklearn hat anscheinend kein WordNGramAnalyzer. Vielleicht müssen Sie mehr Trainingsbeispiele verwenden oder einen anderen Klassifikator ausprobieren? Beachten Sie jedoch, dass der Multi-Label-Klassifizierer erwartet, dass das Ziel eine Liste von Tupeln/Labellisten ist.

Folgendes funktioniert für mich:

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))

Für mich ergibt das die Ausgabe:

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

Hoffe das hilft.

102
mwv

EDIT: Für Python 3 aktualisiert, Scikit-Learn 0.18.1 mit MultiLabelBinarizer wie vorgeschlagen.

Ich habe auch daran gearbeitet und die hervorragende Antwort von mwv ein wenig verbessert, die nützlich sein könnte. Es verwendet Textbeschriftungen als Eingabe anstelle von binären Beschriftungen und kodiert sie mit 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)))

Dies gibt mir folgende Ausgabe:

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
51
J Maurer

Ändern Sie diese Zeile, damit sie in neuen Python-Versionen funktioniert

# lb = preprocessing.LabelBinarizer()
lb = preprocessing.MultiLabelBinarizer()
6
Srini Sydney

Ich bin auch nur darauf gestoßen, und das Problem für mich war, dass mein y_Train eine Folge von Strings war und keine Sequenz von Strings. Offensichtlich wird OneVsRestClassifier basierend auf dem Eingabe-Label-Format entscheiden, ob es sich um mehrere Klassen oder mehrere Etiketten handelt. Also ändern:

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

zu

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

Anscheinend wird dies in Zukunft verschwinden, da die Brüche aller Labels gleich sind: https://github.com/scikit-learn/scikit-learn/pull/1987

6
user2824135

Einige Multi-Klassifizierungsbeispiele sind wie folgt: -

Beispiel 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)

Ausgabe ist 

[[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]]

Beispiel 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)

Ausgabe ist

[[1 0 0]
 [0 1 0]
 [0 0 1]
 [0 1 0]]
1
Goyal Vicky