python - onevsrestclassifier - Use scikit-learn para clasificar en múltiples categorías
multilabel sklearn example (5)
Intento usar uno de los métodos de aprendizaje supervisado de scikit-learn para clasificar fragmentos de texto en una o más categorías. La función de predicción de todos los algoritmos que probé solo devuelve una coincidencia.
Por ejemplo, tengo una pieza de texto:
"Theaters in New York compared to those in London"
Y he entrenado el algoritmo para elegir un lugar para cada fragmento de texto que le doy.
En el ejemplo anterior, me gustaría que devuelva New York
y London
, pero solo devuelve New York
.
¿Es posible usar scikit-learn para devolver resultados múltiples? ¿O incluso devolver la etiqueta con la siguiente probabilidad más alta?
Gracias por tu ayuda.
---Actualizar
Intenté usar OneVsRestClassifier
pero aún así solo recibo una opción por cada fragmento de texto. Debajo está el código de muestra que estoy usando
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
Resultado: [''Nueva York'' ''Londres'' ''Londres'']
Cambie esta línea para que funcione en las nuevas versiones de python
# lb = preprocessing.LabelBinarizer()
lb = preprocessing.MultiLabelBinarizer()
EDITAR: Actualizado para Python 3, scikit-learn 0.18.1 usando MultiLabelBinarizer como se sugiere.
También he estado trabajando en esto y realicé una pequeña mejora en la excelente respuesta de mwv que puede ser útil. Toma etiquetas de texto como entrada en lugar de etiquetas binarias y las codifica utilizando 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)))
Esto me da el siguiente resultado:
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
Lo que quiere se llama clasificación multi-etiqueta. Scikits-learn puede hacer eso. Vea aquí: http://scikit-learn.org/dev/modules/multiclass.html .
No estoy seguro de lo que está pasando mal en su ejemplo, mi versión de sklearn aparentemente no tiene WordNGramAnalyzer. ¿Tal vez se trata de usar más ejemplos de entrenamiento o probar un clasificador diferente? Sin embargo, tenga en cuenta que el clasificador de etiquetas múltiples espera que el destino sea una lista de tuplas / listas de etiquetas.
Lo siguiente funciona para mí:
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))
Para mí, esto produce la salida:
nice day in nyc => New York
welcome to london => London
hello welcome to new york. enjoy it here and london too => New York, London
Espero que esto ayude.
Me topé con esto también, y el problema para mí fue que mi y_Train era una secuencia de cadenas, en lugar de una secuencia de secuencias de String. Aparentemente, OneVsRestClassifier decidirá basándose en el formato de la etiqueta de entrada, ya sea que use multi-clase o multi-etiqueta. Entonces cambia:
y_train = (''New York'',''London'')
a
y_train = ([''New York''],[''London''])
Al parecer, esto desaparecerá en el futuro, ya que se rompe de todas las etiquetas son las mismas: https://github.com/scikit-learn/scikit-learn/pull/1987
Pocos ejemplos de clasificación múltiple son los siguientes:
Ejemplo 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)
La salida es
[[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]]
Ejemplo 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)
La salida es
[[1 0 0]
[0 1 0]
[0 0 1]
[0 1 0]]