Asignación latente de Dirichlet

Modelado de temas:

El modelado de temas es una forma de modelado abstracto para descubrir los ‘temas’ abstractos que ocurren en las colecciones de documentos. La idea es que realizaremos una clasificación no supervisada en diferentes documentos, que encuentran algunos grupos naturales en los temas. Podemos responder a la siguiente pregunta utilizando el modelado de temas.

  • ¿Cuál es el tema/idea principal del documento?
  • Dado un documento, ¿podemos encontrar otro documento con un tema similar?
  • ¿Cómo cambia el campo de temas con el tiempo?

El modelado de temas puede ayudar a optimizar el proceso de búsqueda. En este artículo, discutiremos la asignación latente de Dirichlet, un proceso de modelado de temas.

Asignación latente de Dirichlet

La asignación latente de Dirichlet es uno de los métodos más populares para realizar el modelado de temas. Cada documento consta de varias palabras y cada tema se puede asociar con algunas palabras. El objetivo detrás de la LDA es encontrar temas a los que pertenece el documento, sobre la base de las palabras que contiene. Asume que los documentos con temas similares utilizarán un grupo similar de palabras. Esto permite que los documentos mapeen la distribución de probabilidad sobre temas latentes y los temas son distribución de probabilidad.

Configuración del modelo generativo:

  • Supongamos que tenemos documentos D que usan el vocabulario de tipos de palabras V. Cada documento consta de un token de N palabras (se puede eliminar o rellenar). Ahora, asumimos K temas, esto requiere un vector K-dimensional que represente la distribución de temas para el documento.
  • Cada tema tiene un beta_k multinomial V-dimensional sobre palabras con un previo simétrico común.
  • Para cada tema 1…k:
    • Dibuja un multinomio sobre palabras  \varphi \sim Dir(\beta)      .
  • Para cada documento 1…d:
    • Dibujar un multinomio sobre temas \theta \sim Dir(\alpha)
    • Para cada palabra  w_{N_d}      :
      • Dibujar un tema  Z_{N_d} \sim Mult(\theta_D)       con Z_{N_d} \epsilon [1..K]
      • Dibuja una palabra W_{N_d} \sim Mult(\varphi).

Modelo gráfico de LDA:

P(W,Z,\theta,\varphi, \alpha, \beta) = \prod_{j=1}^{M} P(\theta_j ; \alpha) \prod_{i=1}^{K} P(\varphi_i ; \beta) \prod_{t=1}^{N} P(Z_{j,t} | \theta_j) P(W_{j,t} | \varphi_{Z_{j,t}})

D: \, Number \, of \, Documents \\ N_d: \, Number \, of \, words \, in \, a \, given \, document \\ \beta: \, dirichlet \, prior \, on \, the\, per-document \, topic\, distribution\\ \alpha: \,  dirichlet \, prior \, on \, the\, per-topic \, word\, distribution\\ \theta_i : \, topic \, distribution \, for \, document \, i \\ \varphi_k: \, word \, distribution \, for \, topic \, k \\ z_{ij}: \, topic \, for \, the \, j-th \, word \, in \, document \, i \\ w_{ij}: \, specific \, word.

  • En la ecuación anterior, el LHS representa la probabilidad de generar el documento original desde la máquina LDA.
  • En el lado derecho de la ecuación, hay 4 términos de probabilidad, los primeros dos términos representan la distribución de Dirichlet y los otros dos representan la distribución multinomial. Los términos primero y tercero representan la distribución de temas, pero el segundo y el cuarto representan la distribución de palabras. Discutiremos primero la distribución de Dirichlet.

Distribución Dirichlet

  • La distribución de Dirichlet se puede definir como una densidad de probabilidad para una entrada con valores vectoriales que tiene las mismas características que nuestro parámetro multinomial  \theta       . Tiene valores distintos de cero tales que:

x_1, x_2, ....,x_k \\ where \, x_i \, \epsilon \, (0,1) \, \, \sum_{i=1}^{K}x_i =1

Dir(\theta| \alpha) = \frac{1}{Beta(\alpha)}\prod_{i=1}^{K} \theta_i^{\alpha_i -1} \\ ; where Beta(\alpha) = \frac{\prod_{i=1}^{K} \Gamma(\alpha_i)}{\Gamma(\sum_{i=1}^{K}\alpha_i)} where \alpha =(\alpha_1, \alpha_2,...\alpha_k )

  • α K θ
  • p θ|α θ α?”.

Distribución de Dirichlet

  • Arriba está la visualización de la distribución de Dirichlet, para nuestro propósito, podemos asumir que las esquinas/vértices representan los temas con palabras dentro del triángulo (la palabra está más cerca del tema si se relaciona frecuentemente con él) o viceversa.
  • Esta distribución se puede extender a más de 3 dimensiones. Para 4 dimensiones podemos usar tetraedro y para más dimensiones. Podemos usar k-1 dimensiones simplex.

Inferencia:

  • El problema de inferencia en LDA para calcular el posterior de las variables ocultas dado el documento y el parámetro del corpus \alpha y \beta. Eso es para calcular el P(

Ejemplo:

  • Consideremos que tenemos dos categorías de temas, tenemos un vector de palabras para cada tema que consta de algunas palabras. Las siguientes son las palabras que representan diferentes temas:
palabras P(palabras | tema =1) P(palabras | tema =2)
Corazón 0.2 0
Amor 0.2 0
Alma 0.2 0
Lágrimas 0.2 0
Alegría 0.2 0
Científico 0 0.2
Conocimiento 0 0.2
Trabajar 0 0.2
Investigar 0 0.2
Matemáticas 0 0.2
  • Ahora, tenemos un documento y escaneamos algunos documentos en busca de estas palabras:
Palabras en el documento  {P(tema=1), P(tema=2)}
TRABAJO DE INVESTIGACIÓN DE CONOCIMIENTOS DE MATEMÁTICAS TRABAJO DE INVESTIGACIÓN DE MATEMÁTICAS TRABAJO DE MATEMÁTICAS CIENTÍFICAS {1,0}
CONOCIMIENTO CIENTÍFICO MATEMÁTICAS CORAZÓN CIENTÍFICO LÁGRIMAS DE AMOR CORAZÓN DE CONOCIMIENTO {0,25, 0,75}
MATEMÁTICAS CORAZÓN INVESTIGACIÓN AMOR MATEMÁTICAS TRABAJO LÁGRIMAS ALMA CONOCIMIENTO CORAZÓN {0.5, 0.5}
TRABAJO ALEGRÍA ALMA LÁGRIMAS MATEMÁTICAS LÁGRIMAS AMOR AMOR AMOR ALMA {0,75, 0,25}
LÁGRIMAS AMOR ALEGRÍA ALMA AMOR LÁGRIMAS ALMA ALMA LÁGRIMAS ALEGRÍA  {1,0}
  • Ahora, actualizamos las palabras anteriores a la array de temas utilizando las probabilidades de la array del documento a continuación.

Implementación

En esta implementación, usamos scikit-learn y pyLDAvis. Para los conjuntos de datos, utilizamos conjuntos de datos de reseñas de Yelp que se pueden encontrar en el sitio web de Yelp.

Python3

# install pyldavis
!pip install pyldavis
# imports
!pip install gensim pyLDAvis
! python3 -m spacy download en_core_web_sm
 
import pandas as pd
import numpy as np
 
import string
import spacy
import nltk
 
import gensim
from gensim import corpora
 
import matplotlib.pyplot as plt
 
import pyLDAvis
import pyLDAvis.gensim_models
 
nltk.download('wordnet')
from nltk.corpus import wordnet as wn
nltk.download('stopwords')
from nltk.corpus import stopwords
import spacy.cli
spacy.cli.download("en_core_web_md")
import en_core_web_md
# fetch yelp review dataset and clean it
yelp_review = pd.read_csv('/content/yelp.csv')
yelp_review.head()
# print number of document and topics
print(len(yelp_review))
print("Unique Business")
print(len(yelp_review.groupby('business_id')))
print("Unique User")
print(len(yelp_review.groupby('user_id')))
 
# clean the document and remove punctuation
def clean_text(text):
  delete_dict = {sp_char: '' for sp_char in string.punctuation}
  delete_dict[' '] =' '
  table = str.maketrans(delete_dict)
  text1 = text.translate(table)
  textArr= text1.split()
  text2 = ' '.join([w for w in textArr if ( not w.isdigit() and
                                           ( not w.isdigit() and len(w)>3))])
  return text2.lower()
 
 
 
yelp_review['text'] = yelp_review['text'].apply(clean_text)
yelp_review['Num_words_text'] = yelp_review['text'].apply(lambda x:len(str(x).split()))
 
print('-------Reviews By Stars --------')
print(yelp_review['stars'].value_counts())
print(len(yelp_review))
print('-------------------------')
max_review_data_sentence_length  = yelp_review['Num_words_text'].max()
 
# print short review (
mask = (yelp_review['Num_words_text'] < 100) & (yelp_review['Num_words_text'] >=20)
df_short_reviews = yelp_review[mask]
df_sampled = df_short_reviews.groupby('stars')
    .apply(lambda x: x.sample(n=100)).reset_index(drop = True)
 
print('No of Short reviews')
print(len(df_short_reviews))
 
# function to remove stopwords
def remove_stopwords(text):
    textArr = text.split(' ')
    rem_text = " ".join([i for i in textArr if i not in stop_words])
    return rem_text
 
# remove stopwords from the text
stop_words = stopwords.words('english')
df_sampled['text']=df_sampled['text'].apply(remove_stopwords)
 
# perform Lemmatization
lp = en_core_web_md.load(disable=['parser', 'ner'])
def lemmatization(texts,allowed_postags=['NOUN', 'ADJ']):
       output = []
       for sent in texts:
             doc = nlp(sent)
             output.append([token.lemma_
                            for token in doc if token.pos_ in allowed_postags ])
      return output
text_list=df_sampled['text'].tolist()
print(text_list[2])
tokenized_reviews = lemmatization(text_list)
print(tokenized_reviews[2])
 
# convert to document term frequency:
dictionary = corpora.Dictionary(tokenized_reviews)
doc_term_matrix = [dictionary.doc2bow(rev) for rev in tokenized_reviews]
 
# Creating the object for LDA model using gensim library
LDA = gensim.models.ldamodel.LdaModel
 
# Build LDA model
lda_model = LDA(corpus=doc_term_matrix, id2word=dictionary,
                num_topics=10, random_state=100,
                chunksize=1000, passes=50,iterations=100)
# print lda topics with respect to each word of document
lda_model.print_topics()
 
# calculate perplexity and coherence
print('\Perplexity: ', lda_model.log_perplexity(doc_term_matrix,
                                                total_docs=10000)) 
 
# calculate coherence
coherence_model_lda = CoherenceModel(model=lda_model,
                                     texts=tokenized_reviews, dictionary=dictionary ,
                                     coherence='c_v')
coherence_lda = coherence_model_lda.get_coherence()
print('Coherence: ', coherence_lda)
 
# Now, we use pyLDA vis to visualize it
pyLDAvis.sklearn.prepare(lda_tf, dtm_tf, tf_vectorizer)
Total reviews
10000
Unique Business
4174
Unique User
6403
--------------
-------Reviews by stars --------
4    3526
5    3337
3    1461
2     927
1     749
Name: stars, dtype: int64
10000
-------------------------
No of Short reviews
6276
-------------------------
# review and tokenized version
decided completely write place three times tried closed website posted hours open wants drive suburbs
 youd better call first place cannot trusted wasted time spent hungry minutes walking disappointed vitamin
 fail said

['place', 'time', 'closed', 'website', 'hour', 'open', 'drive', 'suburb', 'first', 'place', 'time', 'hungry', 
'minute', 'vitamin']
---------------------------
# LDA print topics
[(0,
  '0.015*"food" + 0.013*"good" + 0.010*"gelato" + 0.008*"sandwich" + 0.008*"chocolate" + 0.005*"wife" + 0.005*"next" + 0.005*"bad" + 0.005*"night" + 0.005*"sauce"'),
 (1,
  '0.030*"food" + 0.021*"great" + 0.019*"place" + 0.019*"good" + 0.016*"service" + 0.011*"time" + 0.011*"nice" + 0.008*"lunch" + 0.008*"dish" + 0.007*"staff"'),
 (2,
  '0.023*"food" + 0.023*"good" + 0.018*"place" + 0.014*"great" + 0.009*"star" + 0.009*"service" + 0.008*"store" + 0.007*"salad" + 0.007*"well" + 0.006*"pizza"'),
 (3,
  '0.035*"good" + 0.025*"place" + 0.023*"food" + 0.020*"time" + 0.015*"service" + 0.012*"great" + 0.009*"friend" + 0.008*"table" + 0.008*"chicken" + 0.007*"hour"'),
 (4,
  '0.020*"food" + 0.019*"time" + 0.012*"good" + 0.009*"restaurant" + 0.009*"great" + 0.008*"service" + 0.007*"order" + 0.006*"small" + 0.006*"hour" + 0.006*"next"'),
 (5,
  '0.012*"drink" + 0.009*"star" + 0.006*"worth" + 0.006*"place" + 0.006*"friend" + 0.005*"great" + 0.005*"kid" + 0.005*"drive" + 0.005*"simple" + 0.005*"experience"'),
 (6,
  '0.024*"place" + 0.015*"time" + 0.012*"food" + 0.011*"price" + 0.009*"good" + 0.009*"great" + 0.009*"kid" + 0.008*"staff" + 0.008*"nice" + 0.007*"happy"'),
 (7,
  '0.028*"place" + 0.019*"service" + 0.015*"good" + 0.014*"pizza" + 0.014*"time" + 0.013*"food" + 0.013*"great" + 0.011*"well" + 0.009*"order" + 0.007*"price"'),
 (8,
  '0.032*"food" + 0.026*"good" + 0.026*"place" + 0.015*"great" + 0.009*"service" + 0.008*"time" + 0.006*"price" + 0.006*"meal" + 0.006*"shop" + 0.006*"coffee"'),
 (9,
  '0.020*"food" + 0.014*"place" + 0.011*"meat" + 0.010*"line" + 0.009*"good" + 0.009*"minute" + 0.008*"time" + 0.008*"chicken" + 0.008*"wing" + 0.007*"hour"')]
------------------------------

Visualización PyLDAvis

Publicación traducida automáticamente

Artículo escrito por pawangfg y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *