Python para PNL: Trabajar con la biblioteca Gensim (Parte 2)

P

Este es mi undécimo artículo de la serie de artículos sobre Python para PNL y el segundo artículo sobre la biblioteca Gensim de esta serie. En un artículo anterior, proporcioné una breve introducción a la biblioteca Gensim de Python. Expliqué cómo podemos crear diccionarios que mapean palabras a sus correspondientes identificadores numéricos. Además, discutimos cómo crear un corpus de palabras a partir de diccionarios. En este artículo, estudiaremos cómo podemos realizar el modelado de temas utilizando la biblioteca Gensim.

He explicado cómo hacer un modelado de temas usando la biblioteca Scikit-Learn de Python, en mi artículo anterior. En ese artículo, expliqué cómo Asignación de Dirichlet latente (LDA) y Factorización de matriz no negativa (NMF) se puede utilizar para modelar temas.

En este artículo, usaremos la biblioteca Gensim para modelar temas. Los enfoques empleados para el modelado de temas serán LDA y LSI (Indexación latente de Semantim).

Instalación de bibliotecas necesarias

Realizaremos el modelado de temas sobre el texto obtenido de los artículos de Wikipedia. Para raspar los artículos de Wikipedia, usaremos la API de Wikipedia. Para descargar la biblioteca API de Wikipedia, ejecute el siguiente comando:

$ pip install wikipedia

De lo contrario, si usa la distribución Anaconda de Python, puede usar uno de los siguientes comandos:

$ conda install -c conda-forge wikipedia
$ conda install -c conda-forge/label/cf201901 wikipedia

Para visualizar nuestro modelo de tema, usaremos el pyLDAvis biblioteca. Para descargar la biblioteca, ejecute el siguiente comando pip:

$ pip install pyLDAvis

Nuevamente, si usa la distribución Anaconda en su lugar, puede ejecutar uno de los siguientes comandos:

$ conda install -c conda-forge pyldavis
$ conda install -c conda-forge/label/gcc7 pyldavis
$ conda install -c conda-forge/label/cf201901 pyldavis

Modelado de temas con LDA

En esta sección, realizaremos el modelado de temas de los artículos de Wikipedia utilizando LDA.

Descargaremos cuatro artículos de Wikipedia sobre los temas “Calentamiento global”, “Inteligencia artificial”, “Torre Eiffel” y “Mona Lisa”. A continuación, procesaremos previamente los artículos, seguidos del paso de modelado de temas. Finalmente, veremos cómo podemos visualizar el modelo LDA.

Raspado de artículos de Wikipedia

Ejecute el siguiente script:

import wikipedia
import nltk

nltk.download('stopwords')
en_stop = set(nltk.corpus.stopwords.words('english'))

global_warming = wikipedia.page("Global Warming")
artificial_intelligence = wikipedia.page("Artificial Intelligence")
mona_lisa = wikipedia.page("Mona Lisa")
eiffel_tower = wikipedia.page("Eiffel Tower")

corpus = [global_warming.content, artificial_intelligence.content, mona_lisa.content, eiffel_tower.content]

En el script anterior, primero importamos el wikipedia y nltk Bibliotecas. También descargamos el inglés nltk Para las palabras. Usaremos estas palabras vacías más adelante.

A continuación, descargamos el artículo de Wikipedia especificando el tema al page objeto de la wikipedia biblioteca. El objeto devuelto contiene información sobre la página descargada.

Para recuperar el contenido de la página web, podemos utilizar el content atributo. El contenido de los cuatro artículos se almacena en la lista denominada corpus.

Preprocesamiento de datos

Para realizar el modelado de temas a través de LDA, necesitamos un diccionario de datos y el corpus de la bolsa de palabras. Por el último artículo (vinculado arriba), sabemos que para crear un diccionario y un corpus de palabras necesitamos datos en forma de tokens.

Además, debemos eliminar elementos como los signos de puntuación y detener las palabras de nuestro conjunto de datos. En aras de la uniformidad, convertiremos todos los tokens a minúsculas y también los lematizaremos. Además, eliminaremos todos los tokens que tengan menos de 5 caracteres.

Mira el siguiente guión:

import re
from nltk.stem import WordNetLemmatizer

stemmer = WordNetLemmatizer()

def preprocess_text(document):
        # Remove all the special characters
        document = re.sub(r'W', ' ', str(document))

        # remove all single characters
        document = re.sub(r's+[a-zA-Z]s+', ' ', document)

        # Remove single characters from the start
        document = re.sub(r'^[a-zA-Z]s+', ' ', document)

        # Substituting multiple spaces with single space
        document = re.sub(r's+', ' ', document, flags=re.I)

        # Removing prefixed 'b'
        document = re.sub(r'^bs+', '', document)

        # Converting to Lowercase
        document = document.lower()

        # Lemmatization
        tokens = document.split()
        tokens = [stemmer.lemmatize(word) for word in tokens]
        tokens = [word for word in tokens if word not in en_stop]
        tokens = [word for word in tokens if len(word)  > 5]

        return tokens

En el script anterior, creamos un método llamado preprocess_text que acepta un documento de texto como parámetro. El método utiliza operaciones de expresiones regulares para realizar una variedad de tareas. Repasemos brevemente lo que está sucediendo en la función anterior:

document = re.sub(r'W', ' ', str(X[sen]))

La línea anterior reemplaza todos los caracteres especiales y números por un espacio. Sin embargo, cuando elimina los signos de puntuación, aparecen caracteres individuales sin significado en el texto. Por ejemplo, cuando reemplaza la puntuación en el texto Eiffel's, las palabras Eiffel y s Aparecer. Aquí el s no tiene significado, por lo tanto, necesitamos reemplazarlo por el espacio. El siguiente script hace eso:

document = re.sub(r's+[a-zA-Z]s+', ' ', document)

La secuencia de comandos anterior elimina los caracteres individuales dentro del texto solamente. Para eliminar un solo carácter al principio del texto, se utiliza el siguiente código.

document = re.sub(r'^[a-zA-Z]s+', ' ', document)

Cuando elimina espacios simples dentro del texto, pueden aparecer varios espacios vacíos. El siguiente código reemplaza varios espacios vacíos por un solo espacio:

document = re.sub(r's+', ' ', document, flags=re.I)

Cuando raspa un documento en línea, una cadena b a menudo se adjunta al documento, lo que significa que el documento es binario. Para eliminar el prefijo b, se utiliza el siguiente script:

document = re.sub(r'^bs+', '', document)

El resto del método se explica por sí mismo. El documento se convierte en minúsculas y luego se divide en tokens. Los tokens se lematizan y las palabras vacías se eliminan. Finalmente, se ignoran todos los tokens que tienen menos de cinco caracteres. El resto de los tokens se devuelven a la función de llamada.

Temas de modelado

Esta sección es el meollo del artículo. Aquí veremos cómo se puede usar la función incorporada de la biblioteca Gensim para modelar temas. Pero antes de eso, necesitamos crear un corpus de todos los tokens (palabras) en los cuatro artículos de Wikipedia que raspamos. Mira el siguiente guión:

processed_data = [];
for doc in corpus:
    tokens = preprocess_text(doc)
    processed_data.append(tokens)

El guión de arriba es sencillo. Repetimos a través del corpus lista que contiene los cuatro artículos de Wikipedia en forma de cadenas. En cada iteración, pasamos el documento al preprocess_text método que creamos anteriormente. El método devuelve tokens para ese documento en particular. Los tokens se almacenan en el processed_data lista.

Al final de for bucle todos los tokens de los cuatro artículos se almacenarán en el processed_data lista. Ahora podemos usar esta lista para crear un diccionario y el corpus correspondiente de bolsa de palabras. El siguiente script hace eso:

from gensim import corpora

gensim_dictionary = corpora.Dictionary(processed_data)
gensim_corpus = [gensim_dictionary.doc2bow(token, allow_update=True) for token in processed_data]

A continuación, guardaremos nuestro diccionario así como el corpus de la bolsa de palabras usando pickle. Usaremos el diccionario guardado más adelante para hacer predicciones sobre los nuevos datos.

import pickle

pickle.dump(gensim_corpus, open('gensim_corpus_corpus.pkl', 'wb'))
gensim_dictionary.save('gensim_dictionary.gensim')

Ahora, tenemos todo lo necesario para crear el modelo LDA en Gensim. Usaremos el LdaModel clase de la gensim.models.ldamodel módulo para crear el modelo LDA. Necesitamos pasar el corpus de bolsa de palabras que creamos anteriormente como primer parámetro al LdaModel constructor, seguido del número de temas, el diccionario que creamos anteriormente y el número de pasadas (número de iteraciones para el modelo).

Ejecute el siguiente script:

import gensim

lda_model = gensim.models.ldamodel.LdaModel(gensim_corpus, num_topics=4, id2word=gensim_dictionary, passes=20)
lda_model.save('gensim_model.gensim')

Sí, es así de simple. En el script anterior creamos el modelo LDA a partir de nuestro conjunto de datos y lo guardamos.

A continuación, imprimamos 10 palabras para cada tema. Para hacerlo, podemos usar el print_topics método. Ejecute el siguiente script:

topics = lda_model.print_topics(num_words=10)
for topic in topics:
    print(topic)

La salida se ve así:

(0, '0.036*"painting" + 0.018*"leonardo" + 0.009*"louvre" + 0.009*"portrait" + 0.006*"museum" + 0.006*"century" + 0.006*"french" + 0.005*"giocondo" + 0.005*"original" + 0.004*"picture"')

(1, '0.016*"intelligence" + 0.014*"machine" + 0.012*"artificial" + 0.011*"problem" + 0.010*"learning" + 0.009*"system" + 0.008*"network" + 0.007*"research" + 0.007*"knowledge" + 0.007*"computer"')

(2, '0.026*"eiffel" + 0.008*"second" + 0.006*"french" + 0.006*"structure" + 0.006*"exposition" + 0.005*"tallest" + 0.005*"engineer" + 0.004*"design" + 0.004*"france" + 0.004*"restaurant"')

(3, '0.031*"climate" + 0.026*"change" + 0.024*"warming" + 0.022*"global" + 0.014*"emission" + 0.013*"effect" + 0.012*"greenhouse" + 0.011*"temperature" + 0.007*"carbon" + 0.006*"increase"')

El primer tema contiene palabras como painting, louvre, portrait, french museum, etc. Podemos suponer que estas palabras pertenecen a un tema relacionado con una imagen con la conexión francesa.

Del mismo modo, el segundo contiene palabras como intelligence, machine, research, etc. Podemos suponer que estas palabras pertenecen al tema relacionado con la Inteligencia Artificial.

De manera similar, las palabras del tercer y cuarto tópico apuntan al hecho de que estas palabras son parte del tema Torre Eiffel y Calentamiento Global, respectivamente.

Podemos ver claramente que el modelo LDA ha identificado con éxito los cuatro temas en nuestro conjunto de datos.

Es importante mencionar aquí que LDA es un algoritmo de aprendizaje no supervisado y, en problemas del mundo real, no conocerá los temas del conjunto de datos de antemano. Simplemente se le dará un corpus, los temas se crearán usando LDA y luego los nombres de los temas dependerán de usted.

Ahora creemos 8 temas usando nuestro conjunto de datos. Imprimiremos 5 palabras por tema:

lda_model = gensim.models.ldamodel.LdaModel(gensim_corpus, num_topics=8, id2word=gensim_dictionary, passes=15)
lda_model.save('gensim_model.gensim')
topics = lda_model.print_topics(num_words=5)
for topic in topics:
    print(topic)

La salida se ve así:

(0, '0.000*"climate" + 0.000*"change" + 0.000*"eiffel" + 0.000*"warming" + 0.000*"global"')
(1, '0.018*"intelligence" + 0.016*"machine" + 0.013*"artificial" + 0.012*"problem" + 0.010*"learning"')
(2, '0.045*"painting" + 0.023*"leonardo" + 0.012*"louvre" + 0.011*"portrait" + 0.008*"museum"')
(3, '0.000*"intelligence" + 0.000*"machine" + 0.000*"problem" + 0.000*"artificial" + 0.000*"system"')
(4, '0.035*"climate" + 0.030*"change" + 0.027*"warming" + 0.026*"global" + 0.015*"emission"')
(5, '0.031*"eiffel" + 0.009*"second" + 0.007*"french" + 0.007*"structure" + 0.007*"exposition"')
(6, '0.000*"painting" + 0.000*"machine" + 0.000*"system" + 0.000*"intelligence" + 0.000*"problem"')
(7, '0.000*"climate" + 0.000*"change" + 0.000*"global" + 0.000*"machine" + 0.000*"intelligence"')

Nuevamente, la cantidad de temas que desea crear depende de usted. Siga probando con diferentes números hasta que encuentre los temas adecuados. Para nuestro conjunto de datos, el número adecuado de temas es 4, ya que sabemos que nuestro corpus contiene palabras de cuatro artículos diferentes. Vuelva a cuatro temas ejecutando el siguiente script:

lda_model = gensim.models.ldamodel.LdaModel(gensim_corpus, num_topics=4, id2word=gensim_dictionary, passes=20)
lda_model.save('gensim_model.gensim')
topics = lda_model.print_topics(num_words=10)
for topic in topics:
    print(topic)

Esta vez, verá resultados diferentes ya que los valores iniciales para los parámetros LDA se eligen al azar. Los resultados esta vez son los siguientes:

(0, '0.031*"climate" + 0.027*"change" + 0.024*"warming" + 0.023*"global" + 0.014*"emission" + 0.013*"effect" + 0.012*"greenhouse" + 0.011*"temperature" + 0.007*"carbon" + 0.006*"increase"')

(1, '0.026*"eiffel" + 0.008*"second" + 0.006*"french" + 0.006*"structure" + 0.006*"exposition" + 0.005*"tallest" + 0.005*"engineer" + 0.004*"design" + 0.004*"france" + 0.004*"restaurant"')

(2, '0.037*"painting" + 0.019*"leonardo" + 0.009*"louvre" + 0.009*"portrait" + 0.006*"museum" + 0.006*"century" + 0.006*"french" + 0.005*"giocondo" + 0.005*"original" + 0.004*"subject"')

(3, '0.016*"intelligence" + 0.014*"machine" + 0.012*"artificial" + 0.011*"problem" + 0.010*"learning" + 0.009*"system" + 0.008*"network" + 0.007*"knowledge" + 0.007*"research" + 0.007*"computer"')

Puede ver que las palabras del primer tema ahora están relacionadas principalmente con el calentamiento global, mientras que el segundo tema contiene palabras relacionadas con la torre Eiffel.

Evaluación del modelo LDA

Como dije anteriormente, los modelos de aprendizaje no supervisados ​​son difíciles de evaluar ya que no existe una verdad concreta contra la cual podamos probar el resultado de nuestro modelo.

Supongamos que tenemos un nuevo documento de texto y queremos encontrar su tema usando el modelo LDA que acabamos de crear, podemos hacerlo usando el siguiente script:

test_doc="Great structures are build to remember an event happened in the history."
test_doc = preprocess_text(test_doc)
bow_test_doc = gensim_dictionary.doc2bow(test_doc)

print(lda_model.get_document_topics(bow_test_doc))

En el script anterior, creamos una cadena, creamos su representación de diccionario y luego convertimos la cadena en el corpus de bolsa de palabras. La representación de la bolsa de palabras se pasa luego al get_document_topics método. La salida se ve así:

[(0, 0.08422605), (1, 0.7446843), (2, 0.087012805), (3, 0.08407689)]

El resultado muestra que hay un 8.4% de posibilidades de que el nuevo documento pertenezca al tema 1 (consulte las palabras del tema 1 en el último resultado). Asimismo, existe un 74,4% de posibilidades de que este documento pertenezca al segundo tema. Si miramos el segundo tema, contiene palabras relacionadas con la Torre Eiffel. Nuestro documento de prueba también contiene palabras relacionadas con estructuras y edificios. Por tanto, se le ha asignado el segundo tema.

Otra forma de evaluar el modelo LDA es a través de Perplejidad y Puntuación de coherencia.

Como regla general para un buen modelo LDA, la puntuación de perplejidad debe ser baja mientras que la coherencia debe ser alta. La biblioteca Gensim tiene un CoherenceModel clase que se puede utilizar para encontrar la coherencia del modelo LDA. Por perplejidad, el LdaModel el objeto contiene log_perplexity método que toma un corpus de palabras como parámetro y devuelve la perplejidad correspondiente.

print('nPerplexity:', lda_model.log_perplexity(gensim_corpus))

from gensim.models import CoherenceModel

coherence_score_lda = CoherenceModel(model=lda_model, texts=processed_data, dictionary=gensim_dictionary, coherence="c_v")
coherence_score = coherence_score_lda.get_coherence()

print('nCoherence Score:', coherence_score)

los CoherenceModel La clase toma el modelo LDA, el texto tokenizado, el diccionario y el diccionario como parámetros. Para obtener la puntuación de coherencia, get_coherence se utiliza el método. La salida se ve así:

Perplexity: -7.492867099178969

Coherence Score: 0.718387005948207

Visualizando el LDA

Para visualizar nuestros datos, podemos utilizar el pyLDAvis biblioteca que descargamos al principio del artículo. La biblioteca contiene un módulo para el modelo Gensim LDA. Primero debemos preparar la visualización pasando el diccionario, un corpus de bolsa de palabras y el modelo LDA al prepare método. A continuación, debemos llamar al display sobre el gensim módulo de la pyLDAvis biblioteca, como se muestra a continuación:

gensim_dictionary = gensim.corpora.Dictionary.load('gensim_dictionary.gensim')
gensim_corpus = pickle.load(open('gensim_corpus_corpus.pkl', 'rb'))
lda_model = gensim.models.ldamodel.LdaModel.load('gensim_model.gensim')

import pyLDAvis.gensim

lda_visualization = pyLDAvis.gensim.prepare(lda_model, gensim_corpus, gensim_dictionary, sort_topics=False)
pyLDAvis.display(lda_visualization)

En la salida, verá la siguiente visualización:

Cada círculo de la imagen de arriba corresponde a un tema. A partir de la salida del modelo LDA utilizando 4 temas, sabemos que el primer tema está relacionado con el Calentamiento Global, el segundo tema está relacionado con la Torre Eiffel, el tercer tema está relacionado con la Mona Lisa, mientras que el cuarto tema está relacionado con la Artificial. Inteligencia.

La distancia entre círculos muestra cuán diferentes son los temas entre sí. Puede ver que los círculos 2 y 3 se superponen. Esto se debe al hecho de que el tema 2 (Torre Eiffel) y el tema 3 (Mona Lisa) tienen muchas palabras en común, como “francés”, “Francia”, “museo”, “París”, etc.

Si pasa el cursor sobre cualquier palabra de la derecha, solo verá el círculo del tema que contiene la palabra. Por ejemplo, si coloca el cursor sobre la palabra “clima”, verá que los temas 2 y 4 desaparecen porque no contienen la palabra clima. El tamaño del tema 1 aumentará ya que la mayoría de las apariciones de la palabra “clima” están dentro del primer tema. Un porcentaje muy pequeño está en el tema 3, como se muestra en la siguiente imagen:

De manera similar, si mantiene el mouse sobre cualquiera de los círculos, aparecerá una lista de los términos más frecuentes para ese tema a la derecha junto con la frecuencia de aparición en ese mismo tema. Por ejemplo, si coloca el cursor sobre el círculo 2, que corresponde al tema “Torre Eiffel”, verá los siguientes resultados:

En el resultado, puede ver que se ha seleccionado el círculo para el segundo tema, es decir, “Torre Eiffel”. En la lista de la derecha, puede ver los términos más frecuentes para el tema. El término “eiffel” está en la parte superior. Además, es evidente que el término “eiffel” se produjo principalmente dentro de este tema.

Por otro lado, si observa el término “francés”, puede ver claramente que alrededor de la mitad de las ocurrencias del término están dentro de este tema. Esto se debe a que el tema 3, es decir, “Mona Lisa”, también contiene el término “francés” varias veces. Para verificar esto, haga clic en el círculo del tema 3 y coloque el cursor sobre el término “francés”.

Modelado de temas a través de LSI

En la sección anterior, vimos cómo realizar el modelado de temas a través de LDA. Veamos cómo podemos realizar el modelado de temas a través de la indexación semántica latente (LSI).

Para hacerlo, todo lo que tiene que hacer es usar el LsiModel clase. El resto del proceso sigue siendo absolutamente similar a lo que seguimos antes con LDA.

Mira el siguiente guión:

from gensim.models import LsiModel

lsi_model = LsiModel(gensim_corpus, num_topics=4, id2word=gensim_dictionary)
topics = lsi_model.print_topics(num_words=10)
for topic in topics:
    print(topic)

La salida se ve así:

(0, '-0.337*"intelligence" + -0.297*"machine" + -0.250*"artificial" + -0.240*"problem" + -0.208*"system" + -0.200*"learning" + -0.166*"network" + -0.161*"climate" + -0.159*"research" + -0.153*"change"')

(1, '-0.453*"climate" + -0.377*"change" + -0.344*"warming" + -0.326*"global" + -0.196*"emission" + -0.177*"greenhouse" + -0.168*"effect" + 0.162*"intelligence" + -0.158*"temperature" + 0.143*"machine"')

(2, '0.688*"painting" + 0.346*"leonardo" + 0.179*"louvre" + 0.175*"eiffel" + 0.170*"portrait" + 0.147*"french" + 0.127*"museum" + 0.117*"century" + 0.109*"original" + 0.092*"giocondo"')

(3, '-0.656*"eiffel" + 0.259*"painting" + -0.184*"second" + -0.145*"exposition" + -0.145*"structure" + 0.135*"leonardo" + -0.128*"tallest" + -0.116*"engineer" + -0.112*"french" + -0.107*"design"')

Conclusión

El modelado de temas es una tarea importante de PNL. Existe una variedad de enfoques y bibliotecas que se pueden usar para el modelado de temas en Python. En este artículo, vimos cómo hacer un modelado de temas a través de la biblioteca Gensim en Python usando los enfoques LDA y LSI. También vimos cómo visualizar los resultados de nuestro modelo LDA.

 

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