Kit de herramientas de lenguaje natural: clasificación de texto
¿Qué es la clasificación de texto?
La clasificación de texto, como su nombre lo indica, es la forma de clasificar fragmentos de texto o documentos. Pero aquí surge la pregunta de que ¿por qué necesitamos usar clasificadores de texto? Una vez que examinen el uso de palabras en un documento o fragmento de texto, los clasificadores podrán decidir qué etiqueta de clase se le debe asignar.
Clasificador binario
Como su nombre lo indica, el clasificador binario decidirá entre dos etiquetas. Por ejemplo, positivo o negativo. En este, el fragmento de texto o documento puede ser una etiqueta u otra, pero no ambas.
Clasificador de etiquetas múltiples
A diferencia del clasificador binario, el clasificador de etiquetas múltiples puede asignar una o más etiquetas a un fragmento de texto o documento.
Conjunto de funciones etiquetadas versus no etiquetadas
Un mapeo de valores clave de nombres de características a valores de características se denomina conjunto de características. Los conjuntos de características etiquetadas o los datos de entrenamiento son muy importantes para el entrenamiento de clasificación, de modo que luego pueda clasificar el conjunto de características sin etiquetar.
Conjunto de funciones etiquetadas | Conjunto de funciones sin etiquetar |
---|---|
Es una tupla que se parece a (hazaña, etiqueta). | Es una hazaña en sí misma. |
Es una instancia con una etiqueta de clase conocida. | Sin etiqueta asociada, podemos llamarlo instancia. |
Se utiliza para entrenar un algoritmo de clasificación. | Una vez entrenado, el algoritmo de clasificación puede clasificar un conjunto de características sin etiquetar. |
Extracción de características de texto
La extracción de características de texto, como su nombre lo indica, es el proceso de transformar una lista de palabras en un conjunto de características que puede utilizar un clasificador. Debemos tener que transformar nuestro texto en‘dict’ conjuntos de características de estilo porque el Kit de herramientas de lenguaje natural (NLTK) espera ‘dict’ conjuntos de características de estilo.
Modelo de bolsa de palabras (BoW)
BoW, uno de los modelos más simples de NLP, se utiliza para extraer las características de un texto o documento para que pueda usarse en el modelado de algoritmos ML. Básicamente, construye un conjunto de características de presencia de palabras a partir de todas las palabras de una instancia. El concepto detrás de este método es que no le importa cuántas veces aparece una palabra o el orden de las palabras, solo le importa si la palabra está presente en una lista de palabras o no.
Ejemplo
Para este ejemplo, vamos a definir una función llamada bow () -
def bow(words):
return dict([(word, True) for word in words])
Ahora, llamemos bow()función en palabras. Guardamos estas funciones en un archivo llamado bagwords.py.
from bagwords import bow
bow(['we', 'are', 'using', 'tutorialspoint'])
Salida
{'we': True, 'are': True, 'using': True, 'tutorialspoint': True}
Clasificadores de entrenamiento
En secciones anteriores, aprendimos cómo extraer características del texto. Entonces ahora podemos entrenar a un clasificador. El primer clasificador y el más sencillo esNaiveBayesClassifier clase.
Clasificador Naïve Bayes
Para predecir la probabilidad de que un conjunto de características dado pertenezca a una etiqueta particular, utiliza el teorema de Bayes. La fórmula del teorema de Bayes es la siguiente.
$$ P (A | B) = \ frac {P (B | A) P (A)} {P (B)} $$Aquí,
P(A|B) - También se denomina probabilidad posterior, es decir, la probabilidad de que ocurra el primer evento, es decir, A, dado que ocurrió el segundo evento, es decir, B.
P(B|A) - Es la probabilidad de que el segundo evento, es decir, B ocurra después del primer evento, es decir, A ocurrió.
P(A), P(B) - También se denomina probabilidad previa, es decir, la probabilidad de que ocurra el primer evento, es decir, A o el segundo, es decir, B.
Para entrenar el clasificador Naïve Bayes, usaremos el movie_reviewscorpus de NLTK. Este corpus tiene dos categorías de texto, a saber:pos y neg. Estas categorías hacen que un clasificador entrenado en ellas sea un clasificador binario. Cada archivo del corpus se compone de dos, uno es una reseña de película positiva y otro es una reseña de película negativa. En nuestro ejemplo, usaremos cada archivo como una única instancia tanto para entrenar como para probar el clasificador.
Ejemplo
Para el clasificador de entrenamiento, necesitamos una lista de conjuntos de características etiquetados, que tendrá el formato [(featureset, label)]. Aquí elfeatureset variable es una dict y la etiqueta es la etiqueta de clase conocida para el featureset. Vamos a crear una función llamadalabel_corpus() que tomará un corpus llamado movie_reviewsy también una función llamada feature_detector, que por defecto es bag of words. Construirá y devolverá un mapeo del formulario, {etiqueta: [conjunto de características]}. Después de eso, usaremos este mapeo para crear una lista de instancias de entrenamiento etiquetadas e instancias de prueba.
import collections
def label_corpus(corp, feature_detector=bow):
label_feats = collections.defaultdict(list)
for label in corp.categories():
for fileid in corp.fileids(categories=[label]):
feats = feature_detector(corp.words(fileids=[fileid]))
label_feats[label].append(feats)
return label_feats
Con la ayuda de la función anterior obtendremos un mapeo {label:fetaureset}. Ahora vamos a definir una función más llamadasplit que tomará un mapeo devuelto por label_corpus() función y divide cada lista de conjuntos de características en entrenamiento etiquetado, así como en instancias de prueba.
def split(lfeats, split=0.75):
train_feats = []
test_feats = []
for label, feats in lfeats.items():
cutoff = int(len(feats) * split)
train_feats.extend([(feat, label) for feat in feats[:cutoff]])
test_feats.extend([(feat, label) for feat in feats[cutoff:]])
return train_feats, test_feats
Ahora, usemos estas funciones en nuestro corpus, es decir, movietitis -
from nltk.corpus import movie_reviews
from featx import label_feats_from_corpus, split_label_feats
movie_reviews.categories()
Salida
['neg', 'pos']
Ejemplo
lfeats = label_feats_from_corpus(movie_reviews)
lfeats.keys()
Salida
dict_keys(['neg', 'pos'])
Ejemplo
train_feats, test_feats = split_label_feats(lfeats, split = 0.75)
len(train_feats)
Salida
1500
Ejemplo
len(test_feats)
Salida
500
Lo hemos visto en movie_reviewscorpus, hay 1000 archivos pos y 1000 archivos neg. También terminamos con 1500 instancias de capacitación etiquetadas y 500 instancias de prueba etiquetadas.
Ahora entrenemos NaïveBayesClassifier usando su train() método de clase -
from nltk.classify import NaiveBayesClassifier
NBC = NaiveBayesClassifier.train(train_feats)
NBC.labels()
Salida
['neg', 'pos']
Clasificador de árbol de decisión
Otro clasificador importante es el clasificador de árbol de decisión. Aquí para entrenarloDecisionTreeClassifierclase creará una estructura de árbol. En esta estructura de árbol, cada nodo corresponde a un nombre de característica y las ramas corresponden a los valores de característica. Y bajando las ramas llegaremos a las hojas del árbol, es decir, las etiquetas de clasificación.
Para entrenar el clasificador del árbol de decisión, usaremos las mismas características de entrenamiento y prueba, es decir train_feats y test_feats, variables que hemos creado a partir de movie_reviews cuerpo.
Ejemplo
Para entrenar este clasificador, llamaremos DecisionTreeClassifier.train() método de clase de la siguiente manera:
from nltk.classify import DecisionTreeClassifier
decisiont_classifier = DecisionTreeClassifier.train(
train_feats, binary = True, entropy_cutoff = 0.8,
depth_cutoff = 5, support_cutoff = 30
)
accuracy(decisiont_classifier, test_feats)
Salida
0.725
Clasificador de máxima entropía
Otro clasificador importante es MaxentClassifier que también se conoce como conditional exponential classifier o logistic regression classifier. Aquí para entrenarlo, elMaxentClassifier class convertirá conjuntos de características etiquetados en vectores usando codificación.
Para entrenar el clasificador del árbol de decisión, usaremos las mismas características de entrenamiento y prueba, es decir train_featsy test_feats, variables que hemos creado a partir de movie_reviews cuerpo.
Ejemplo
Para entrenar este clasificador, llamaremos MaxentClassifier.train() método de clase de la siguiente manera:
from nltk.classify import MaxentClassifier
maxent_classifier = MaxentClassifier
.train(train_feats,algorithm = 'gis', trace = 0, max_iter = 10, min_lldelta = 0.5)
accuracy(maxent_classifier, test_feats)
Salida
0.786
Clasificador de Scikit-learn
Una de las mejores bibliotecas de aprendizaje automático (ML) es Scikit-learn. En realidad, contiene todo tipo de algoritmos ML para varios propósitos, pero todos tienen el mismo patrón de diseño de ajuste de la siguiente manera:
- Ajustar el modelo a los datos
- Y usa ese modelo para hacer predicciones
En lugar de acceder directamente a los modelos de scikit-learn, aquí usaremos NLTK's SklearnClassifierclase. Esta clase es una clase contenedora en torno a un modelo scikit-learn para que se ajuste a la interfaz Classifier de NLTK.
Seguiremos los siguientes pasos para capacitar a un SklearnClassifier clase -
Step 1 - Primero crearemos funciones de entrenamiento como hicimos en recetas anteriores.
Step 2 - Ahora, elija e importe un algoritmo de Scikit-learn.
Step 3 - A continuación, necesitamos construir un SklearnClassifier class con el algoritmo elegido.
Step 4 - Por último, entrenaremos SklearnClassifier clase con nuestras funciones de entrenamiento.
Implementemos estos pasos en la siguiente receta de Python:
from nltk.classify.scikitlearn import SklearnClassifier
from sklearn.naive_bayes import MultinomialNB
sklearn_classifier = SklearnClassifier(MultinomialNB())
sklearn_classifier.train(train_feats)
<SklearnClassifier(MultinomialNB(alpha = 1.0,class_prior = None,fit_prior = True))>
accuracy(sk_classifier, test_feats)
Salida
0.885
Medición de precisión y recuperación
Durante el entrenamiento de varios clasificadores, también hemos medido su precisión. Pero además de la precisión, existen otras métricas que se utilizan para evaluar los clasificadores. Dos de estas métricas sonprecision y recall.
Ejemplo
En este ejemplo, vamos a calcular la precisión y la recuperación de la clase NaiveBayesClassifier que entrenamos anteriormente. Para lograr esto, crearemos una función llamada metrics_PR () que tomará dos argumentos, uno es el clasificador entrenado y el otro son las características de prueba etiquetadas. Ambos argumentos son los mismos que pasamos al calcular la precisión de los clasificadores:
import collections
from nltk import metrics
def metrics_PR(classifier, testfeats):
refsets = collections.defaultdict(set)
testsets = collections.defaultdict(set)
for i, (feats, label) in enumerate(testfeats):
refsets[label].add(i)
observed = classifier.classify(feats)
testsets[observed].add(i)
precisions = {}
recalls = {}
for label in classifier.labels():
precisions[label] = metrics.precision(refsets[label],testsets[label])
recalls[label] = metrics.recall(refsets[label], testsets[label])
return precisions, recalls
Llamemos a esta función para encontrar la precisión y recordar:
from metrics_classification import metrics_PR
nb_precisions, nb_recalls = metrics_PR(nb_classifier,test_feats)
nb_precisions['pos']
Salida
0.6713532466435213
Ejemplo
nb_precisions['neg']
Salida
0.9676271186440678
Ejemplo
nb_recalls['pos']
Salida
0.96
Ejemplo
nb_recalls['neg']
Salida
0.478
Combinación de clasificador y votación
La combinación de clasificadores es una de las mejores formas de mejorar el rendimiento de la clasificación. Y votar es una de las mejores formas de combinar varios clasificadores. Para votar necesitamos tener un número impar de clasificadores. En la siguiente receta de Python, vamos a combinar tres clasificadores, a saber, la clase NaiveBayesClassifier, la clase DecisionTreeClassifier y la clase MaxentClassifier.
Para lograr esto, vamos a definir una función llamada vote_classifiers () de la siguiente manera.
import itertools
from nltk.classify import ClassifierI
from nltk.probability import FreqDist
class Voting_classifiers(ClassifierI):
def __init__(self, *classifiers):
self._classifiers = classifiers
self._labels = sorted(set(itertools.chain(*[c.labels() for c in classifiers])))
def labels(self):
return self._labels
def classify(self, feats):
counts = FreqDist()
for classifier in self._classifiers:
counts[classifier.classify(feats)] += 1
return counts.max()
Llamemos a esta función para combinar tres clasificadores y encontrar la precisión:
from vote_classification import Voting_classifiers
combined_classifier = Voting_classifiers(NBC, decisiont_classifier, maxent_classifier)
combined_classifier.labels()
Salida
['neg', 'pos']
Ejemplo
accuracy(combined_classifier, test_feats)
Salida
0.948
De la salida anterior, podemos ver que los clasificadores combinados obtuvieron la mayor precisión que los clasificadores individuales.