Python para PNL: modelado de temas

P

Este es el sexto artículo de mi serie de artículos sobre Python para PNL. En mi artículo anterior, hablé sobre cómo realizar análisis de sentimientos de los datos de Twitter utilizando la biblioteca Scikit-Learn de Python. En este artículo, estudiaremos el modelado de temas, que es otra aplicación muy importante de la PNL. Veremos cómo hacer modelado de temas con Python.

¿Qué es el modelado de temas?

El modelado de temas es una técnica no supervisada que pretende analizar grandes volúmenes de datos de texto agrupando los documentos en grupos. En el caso del modelado de temas, los datos de texto no tienen etiquetas adjuntas. Más bien, el modelado de temas intenta agrupar los documentos en grupos basados ​​en características similares.

Un ejemplo típico de modelado de temas es agrupar una gran cantidad de artículos de periódicos que pertenecen a la misma categoría. En otras palabras, agrupar documentos que tengan el mismo tema. Es importante mencionar aquí que es extremadamente difícil evaluar el desempeño del modelado de temas ya que no hay respuestas correctas. Depende del usuario encontrar características similares entre los documentos de un grupo y asignarle una etiqueta o tema apropiado.

Se utilizan principalmente dos enfoques para el modelado de temas: Asignación de Dirichlet latente y Factorización de matriz no negativa. En las siguientes secciones, revisaremos brevemente ambos enfoques y veremos cómo se pueden aplicar al modelado de temas en Python.

Asignación de Dirichlet latente (LDA)

La LDA se basa en dos supuestos generales:

  • Los documentos que tienen palabras similares suelen tener el mismo tema
  • Los documentos que tienen grupos de palabras que aparecen juntas con frecuencia suelen tener el mismo tema.

Estos supuestos tienen sentido porque los documentos que tienen el mismo tema, por ejemplo, Temas comerciales, tendrán palabras como “economía”, “ganancias”, “mercado de valores”, “pérdidas”, etc. El segundo supuesto establece que si estos las palabras suelen aparecer juntas en varios documentos, esos documentos pueden pertenecer a la misma categoría.

Matemáticamente, los dos supuestos anteriores se pueden representar como:

  • Los documentos son distribuciones de probabilidad sobre temas latentes
  • Los temas son distribuciones de probabilidad sobre palabras.

LDA para modelado de temas en Python

En esta sección veremos cómo se puede usar Python para implementar LDA para el modelado de temas. El conjunto de datos se puede descargar del Kaggle.

El conjunto de datos contiene reseñas de usuarios para diferentes productos en la categoría de alimentos. Usaremos LDA para agrupar las reseñas de los usuarios en 5 categorías.

El primer paso, como siempre, es importar el conjunto de datos junto con las bibliotecas necesarias. Ejecute el siguiente script para hacerlo:

import pandas as pd
import numpy as np

reviews_datasets = pd.read_csv(r'E:DatasetsReviews.csv')
reviews_datasets = reviews_datasets.head(20000)
reviews_datasets.dropna()

En el script de arriba, importamos el conjunto de datos usando el read_csv método de la biblioteca de pandas. El conjunto de datos original contiene alrededor de 500.000 reseñas. Sin embargo, debido a limitaciones de memoria, realizaré LDA solo en los primeros 20k registros. En el script anterior, filtramos las primeras 20k filas y luego eliminamos los valores nulos del conjunto de datos.

A continuación, imprimimos las primeras cinco filas del conjunto de datos usando el head() función para inspeccionar nuestros datos:

reviews_datasets.head()

En la salida, verá los siguientes datos:

Aplicaremos LDA en la columna “Texto” ya que contiene las revisiones, el resto de las columnas serán ignoradas.

Veamos la revisión número 350.

reviews_datasets['Text'][350]

En el resultado, verá el siguiente texto de revisión:

'These chocolate covered espresso beans are wonderful!  The chocolate is very dark and rich and the "bean" inside is a very delightful blend of flavors with just enough caffine to really give it a zing.'

Antes de que podamos aplicar LDA, necesitamos crear vocabulario de todas las palabras en nuestros datos. Recuerde del artículo anterior, podríamos hacerlo con la ayuda de un vectorizador de conteo. Mira el siguiente guión:

from sklearn.feature_extraction.text import CountVectorizer

count_vect = CountVectorizer(max_df=0.8, min_df=2, stop_words="english")
doc_term_matrix = count_vect.fit_transform(reviews_datasets['Text'].values.astype('U'))

En el script de arriba usamos el CountVectorizer clase de la sklearn.feature_extraction.text módulo para crear una matriz documento-plazo. Especificamos incluir solo aquellas palabras que aparecen en menos del 80% del documento y aparecen en al menos 2 documentos. También eliminamos todas las palabras vacías, ya que en realidad no contribuyen al modelado de temas.

Ahora veamos nuestra matriz de términos del documento:

doc_term_matrix

Salida:

<20000x14546 sparse matrix of type '<class 'numpy.int64'>'
with 594703 stored elements in Compressed Sparse Row format>

Cada uno de los 20k documentos se representa como un vector dimensional 14546, lo que significa que nuestro vocabulario tiene 14546 palabras.

A continuación, usaremos LDA para crear temas junto con la distribución de probabilidad de cada palabra en nuestro vocabulario para cada tema. Ejecute el siguiente script:

from sklearn.decomposition import LatentDirichletAllocation

LDA = LatentDirichletAllocation(n_components=5, random_state=42)
LDA.fit(doc_term_matrix)

En el script de arriba usamos el LatentDirichletAllocation clase de la sklearn.decomposition biblioteca para realizar LDA en nuestra matriz de documentos y términos. El parámetro n_components especifica el número de categorías o temas en los que queremos que se divida nuestro texto. El parámetro random_state (también conocido como el semilla) se establece en 42 para que obtenga resultados similares a los míos.

Busquemos palabras al azar de nuestro vocabulario. Sabemos que el vectorizador de conteo contiene todas las palabras de nuestro vocabulario. Podemos usar el get_feature_names() y pasarle el ID de la palabra que queremos obtener.

El siguiente guión extrae aleatoriamente 10 palabras de nuestro vocabulario:

import random

for i in range(10):
    random_id = random.randint(0,len(count_vect.get_feature_names()))
    print(count_vect.get_feature_names()[random_id])

La salida se ve así:

bribe
tarragon
qualifies
prepare
hangs
noted
churning
breeds
zon
chunkier

Busquemos 10 palabras con la mayor probabilidad para el primer tema. Para obtener el primer tema, puede utilizar el components_ atributo y pasar un índice 0 como valor:

first_topic = LDA.components_[0]

El primer tema contiene las probabilidades de 14546 palabras para el tema 1. Para ordenar los índices según los valores de probabilidad, podemos usar el argsort() función. Una vez ordenadas, las 10 palabras con las mayores probabilidades ahora pertenecerán a los últimos 10 índices de la matriz. El siguiente script devuelve los índices de las 10 palabras con las mayores probabilidades:

top_topic_words = first_topic.argsort()[-10:]

Salida:

array([14106,  5892,  7088,  4290, 12596,  5771,  5187, 12888,  7498,
       12921], dtype=int64)

Estos índices se pueden utilizar para recuperar el valor de las palabras del count_vect objeto, que se puede hacer así:

for i in top_topic_words:
    print(count_vect.get_feature_names()[i])

En el resultado, debería ver las siguientes palabras:

water
great
just
drink
sugar
good
flavor
taste
like
tea

Las palabras muestran que el primer tema podría ser sobre el té.

Imprimamos las 10 palabras con mayores probabilidades para los cinco temas:

for i,topic in enumerate(LDA.components_):
    print(f'Top 10 words for topic #{i}:')
    print([count_vect.get_feature_names()[i] for i in topic.argsort()[-10:]])
    print('n')

La salida se ve así:

Top 10 words for topic #0:
['water', 'great', 'just', 'drink', 'sugar', 'good', 'flavor', 'taste', 'like', 'tea']


Top 10 words for topic #1:
['br', 'chips', 'love', 'flavor', 'chocolate', 'just', 'great', 'taste', 'good', 'like']


Top 10 words for topic #2:
['just', 'drink', 'orange', 'sugar', 'soda', 'water', 'like', 'juice', 'product', 'br']


Top 10 words for topic #3:
['gluten', 'eat', 'free', 'product', 'like', 'dogs', 'treats', 'dog', 'br', 'food']


Top 10 words for topic #4:
['cups', 'price', 'great', 'like', 'amazon', 'good', 'br', 'product', 'cup', 'coffee']

El resultado muestra que el segundo tema podría contener reseñas sobre chocolates, etc. De manera similar, el tercer tema podría contener nuevamente reseñas sobre refrescos o jugos. Puede ver que hay algunas palabras comunes en todas las categorías. Esto se debe a que hay pocas palabras que se utilizan para casi todos los temas. Por ejemplo, “bueno”, “excelente”, “me gusta”, etc.

Como paso final, agregaremos una columna al marco de datos original que almacenará el tema del texto. Para hacerlo, podemos usar LDA.transform() y páselo a nuestra matriz de documentos y términos. Este método asignará la probabilidad de todos los temas a cada documento. Mira el siguiente código:

topic_values = LDA.transform(doc_term_matrix)
topic_values.shape

En la salida, verá (20000, 5) lo que significa que cada uno de los documentos tiene 5 columnas donde cada columna corresponde al valor de probabilidad de un tema en particular. Para encontrar el índice de tema con valor máximo, podemos llamar al argmax() y pase 1 como valor para el parámetro del eje.

La siguiente secuencia de comandos agrega una nueva columna para el tema en el marco de datos y asigna el valor del tema a cada fila de la columna:

reviews_datasets['Topic'] = topic_values.argmax(axis=1)

Veamos ahora cómo se ve el conjunto de datos:

reviews_datasets.head()

Salida:

Puede ver una nueva columna para el tema en la salida.

Factorización de matriz no negativa (NMF)

En la sección anterior, vimos cómo se puede usar LDA para modelar temas. En esta sección, veremos cómo se puede utilizar la factorización matricial no negativa para el modelado de temas.

La factorización matricial no negativa también es una técnica de aprendizaje supervisado que realiza agrupaciones y reducciones de dimensionalidad. Se puede utilizar en combinación con el esquema TF-IDF para realizar el modelado de temas. En esta sección, veremos cómo se puede usar Python para realizar una factorización matricial no negativa para el modelado de temas.

NMF para modelado de temas en Python

En esta sección, realizaremos el modelado de temas en el mismo conjunto de datos que usamos en la última sección. Verás que los pasos también son bastante similares.

Comenzamos importando el conjunto de datos:

import pandas as pd
import numpy as np

reviews_datasets = pd.read_csv(r'E:DatasetsReviews.csv')
reviews_datasets = reviews_datasets.head(20000)
reviews_datasets.dropna()

En la sección anterior usamos el vectorizador de conteo, pero en esta sección usaremos el vectorizador TFIDF ya que NMF trabaja con TFIDF. Crearemos una matriz de términos del documento con TFIDF. Mira el siguiente guión:

from sklearn.feature_extraction.text import TfidfVectorizer

tfidf_vect = TfidfVectorizer(max_df=0.8, min_df=2, stop_words="english")
doc_term_matrix = tfidf_vect.fit_transform(reviews_datasets['Text'].values.astype('U'))

Una vez que se genera la matriz de términos del documento, podemos crear una matriz de probabilidad que contiene probabilidades de todas las palabras en el vocabulario para todos los temas. Para hacerlo, podemos usar el NMF clase de la sklearn.decomposition módulo. Mira el siguiente guión:

from sklearn.decomposition import NMF

nmf = NMF(n_components=5, random_state=42)
nmf.fit(doc_term_matrix )

Como hicimos en la sección anterior, obtengamos al azar 10 palabras de nuestro vocabulario:

import random

for i in range(10):
    random_id = random.randint(0,len(tfidf_vect.get_feature_names()))
    print(tfidf_vect.get_feature_names()[random_id])

En la salida, verá las siguientes palabras:

safest
pith
ache
formula
fussy
frontier
burps
speaker
responsibility
dive

A continuación, recuperaremos el vector de probabilidad de palabras para el primer tema y recuperaremos los índices de las diez palabras con las mayores probabilidades:

first_topic = nmf.components_[0]
top_topic_words = first_topic.argsort()[-10:]

Estos índices ahora se pueden pasar al tfidf_vect objeto para recuperar las palabras reales. Mira el siguiente guión:

for i in top_topic_words:
    print(tfidf_vect.get_feature_names()[i])

La salida se ve así:

really
chocolate
love
flavor
just
product
taste
great
good
like

Las palabras para el tema 1 muestran que el tema 1 puede contener reseñas de chocolates. Imprimamos ahora las diez palabras con mayores probabilidades para cada uno de los temas:

for i,topic in enumerate(nmf.components_):
    print(f'Top 10 words for topic #{i}:')
    print([tfidf_vect.get_feature_names()[i] for i in topic.argsort()[-10:]])
    print('n')

La salida del script anterior se ve así:

Top 10 words for topic #0:
['really', 'chocolate', 'love', 'flavor', 'just', 'product', 'taste', 'great', 'good', 'like']


Top 10 words for topic #1:
['like', 'keurig', 'roast', 'flavor', 'blend', 'bold', 'strong', 'cups', 'cup', 'coffee']


Top 10 words for topic #2:
['com', 'amazon', 'orange', 'switch', 'water', 'drink', 'soda', 'sugar', 'juice', 'br']


Top 10 words for topic #3:
['bags', 'flavor', 'drink', 'iced', 'earl', 'loose', 'grey', 'teas', 'green', 'tea']


Top 10 words for topic #4:
['old', 'love', 'cat', 'eat', 'treat', 'loves', 'dogs', 'food', 'treats', 'dog']

Las palabras para el tema 1 muestran que este tema contiene reseñas sobre el café. De manera similar, las palabras del tema 2 describen que contiene reseñas sobre refrescos y jugos. El tema 3 nuevamente contiene reseñas sobre bebidas. Por último, el tema 4 puede contener reseñas sobre alimentos para animales, ya que contiene palabras como “gato”, “perro”, “golosina”, etc.

La siguiente secuencia de comandos agrega los temas al conjunto de datos y muestra las primeras cinco filas:

topic_values = nmf.transform(doc_term_matrix)
reviews_datasets['Topic'] = topic_values.argmax(axis=1)
reviews_datasets.head()

La salida del código anterior se ve así:

Como puede ver, a cada revisión se le ha asignado un tema, que se generó mediante el método NMF.

Conclusión

El modelado de temas es una de las áreas de investigación más buscadas en PNL. Se utiliza para agrupar grandes volúmenes de datos de texto sin etiquetar. En este artículo, se explicaron dos enfoques para el modelado de temas. En este artículo vimos cómo la asignación de Dirichlet latente y la factorización de matrices no negativas se pueden usar para el modelado de temas con la ayuda de bibliotecas de Python.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad