본문 바로가기
Study

[NLP] 6. Topic Modeling

by Hwanin99 2024. 8. 21.
  • 토픽 모델링은 문서 집합에서 주제를 찾아내기 위한 기술이다.
  • 토픽 모델링은 '특정 주제에 관한 문서에서는 특정 단어가 자주 등장할 것이다.' 라는 직관을 기반으로 한다.
    • 예를 들어, 주제가 '개'인 문서에서는 개의 품종, 개의 특성을 나타내는 단어가 다른 문서에 비해 많이 등장한다.
    • 주로 사용되는 토픽 모델링 방법은 잠재 의미 분석과 잠재 디리클레 할당 기법이 있다.

1. 잠재 의미 분석(Latent Semantic Analysis)

  • 잠재 의미 분석(LSA)은 주로 문서 색인의 의미 검색에 사용된다.
    • 잠재 의미 인덱싱(Latent Semantic Indexing, LSI)로도 알려져 있다.
  • LSA의 목표는 문서와 단어의 기반이 되는 잠재적인 토픽을 발견하는 것이다.
  • 잠재적인 토픽은 문서에 있는 단어들의 분포를 주도한다고 가정한다.

 

  • LSA 방법
    • 문서 모음에서 생성한 DTM에서 단어-토픽 행렬과 토픽-중요도 행렬, 그리고 토픽-문서 행렬로 분해한다.

2. 잠재 디리클레 할당(Latent Dirichlet Allocation)

  • 잠재 디리클레 할당(LDA)는 대표적인 토픽 모델링 알고리즘 중 하나이다.

 

  • 잠재 디리클레 할당 방법
    • 사용자가 토픽이 개수를 지정해 알고리즘에 전달한다.
    • 모든 단어들을 토픽 중 하나에 할당한다.
    • 모든 문서의 모든 단어에 대해 단어 $w$가 가정에 의거, $p(t|d),p(w|t)$에 따라 토픽을 재할당, 이를 반복한다.
      • 이때, 가정은 자신만이 잘못된 토픽에 할당되어 있고 다른 모든 단어는 올바른 토픽에 할당된다는 것을 의미한다.
    • $p(t|d)$: 문서 $d$의 단어들 중 토픽 $t$에 해당하는 비율
      • 해당 문서의 자주 등장하는 다른 단어의 토픽이 해당 단어의 토픽이 될 가능성이 높음을 의미한다.
    • $p(w|t)$: 단어 $w$를 가지고 있는 모든 문서들 중 토픽 $t$가 할당된 비율  
      • 다른 문서에서 단어 $w$에 많이 할당된 토픽이 해당 단어의 토픽이 될 가능성이 높음을 의미한다.

데이터 준비

from sklearn.datasets import fetch_20newsgroups

dataset=fetch_20newsgroups(shuffle=True,random_state=1,
                           remove=('headers','footers','quotes'))
documents=dataset.data

print(len(documents))
-----------------------------------------------------------------
11314

 

import re
import nltk
from nltk.corpus import stopwords
from gensim.parsing.preprocessing import preprocess_string

nltk.download('popular')

def clean_text(d):
  pattern=r'[^a-zA-Z\s]'
  text=re.sub(pattern,'',d)
  return d

def clean_stopword(d):
  stop_words=stopwords.words('english')
  return ' '.join([w.lower() for w in d.split() if w not in stop_words and len(w)>3])

def preprocessing(d):
  return preprocess_string(d)
import pandas as pd

news_df=pd.DataFrame({'article':documents})
len(news_df)
-------------------------------------------
11314
news_df.replace('',float('NaN'),inplace=True)
#news_df.isnull().values
news_df.dropna(inplace=True)
print(len(news_df))
---------------------------------------------
11096

 

news_df['article']=news_df['article'].apply(clean_text)
news_df['article']
--------------------------------------------------------
0        Well i'm not sure about the story nad it did s...
1        \n\n\n\n\n\n\nYeah, do you expect people to re...
2        Although I realize that principle is not one o...
3        Notwithstanding all the legitimate fuss about ...
4        Well, I will have to change the scoring on my ...
                               ...                        
11309    Danny Rubenstein, an Israeli journalist, will ...
11310                                                   \n
11311    \nI agree.  Home runs off Clemens are always m...
11312    I used HP DeskJet with Orange Micros Grappler ...
11313                                          ^^^^^^\n...
Name: article, Length: 11096, dtype: object
news_df['article']=news_df['article'].apply(clean_stopword)
news_df['article']
-----------------------------------------------------------
0        well sure story seem biased. what disagree sta...
1        yeah, expect people read faq, etc. actually ac...
2        although realize principle strongest points, w...
3        notwithstanding legitimate fuss proposal, much...
4        well, change scoring playoff pool. unfortunate...
                               ...                        
11309    danny rubenstein, israeli journalist, speaking...
11310                                                     
11311    agree. home runs clemens always memorable. kin...
11312    used deskjet orange micros grappler system6.0....
11313    ^^^^^^ argument murphy. scared hell came last ...
Name: article, Length: 11096, dtype: object

 

import numpy as np

tokenized_news=news_df['article'].apply(preprocessing)
tokenized_news=tokenized_news.to_list()

drop_news=[index for index,sentence in enumerate(tokenized_news) if len(sentence)<=1]
news_texts=np.delete(tokenized_news,drop_news,axis=0)
print(len(news_texts))
-------------------------------------------------------------------------------------
10936

3. Gensim을 이용한 토픽 모델링

from gensim import corpora

dictionary=corpora.Dictionary(news_texts)
corpus=[dictionary.doc2bow(text) for text in news_texts]

잠재 의미 분석을 위한 LSI Model

from gensim.models import LsiModel

lsi_model=LsiModel(corpus,num_topics=20,id2word=dictionary)
topics=lsi_model.print_topics()
from gensim.models.coherencemodel import CoherenceModel

min_topics,max_topics=20,25
coherence_scores=[]

for num_topics in range(min_topics,max_topics):
  model=LsiModel(corpus,num_topics=num_topics,id2word=dictionary)
  coherence=CoherenceModel(model=model,
                           texts=news_texts,
                           dictionary=dictionary)
  coherence_scores.append(coherence.get_coherence())

print(coherence_scores)
-----------------------------------------------------------------
[0.40321580534857937, 0.5223481236448774, 0.5252363114651399, 0.46535514465376476, 0.497176889138825]

 

import matplotlib.pyplot as plt
plt.style.use('seaborn-white')

x=[int(i) for i in range(min_topics,max_topics)]

plt.figure(figsize=(10,5))
plt.plot(x,coherence_scores)
plt.xlabel('Number of Topics')
plt.ylabel('Coherence Scores')
plt.show()

잠재 의미 분석을 위한 LSI Model 그래프


잠재 디리클레 할당을 위한 LDA Model

from gensim.models import LdaModel

lda_model=LdaModel(corpus,num_topics=20,id2word=dictionary)
topics=lda_model.print_topics()
from gensim.models.coherencemodel import CoherenceModel

min_topics,max_topics=20,25
coherence_scores=[]

for num_topics in range(min_topics,max_topics):
  model=LsiModel(corpus,num_topics=num_topics,id2word=dictionary)
  coherence=CoherenceModel(model=model,
                           texts=news_texts,
                           dictionary=dictionary)
  coherence_scores.append(coherence.get_coherence())

print(coherence_scores)
-----------------------------------------------------------------
[0.47646517548183837, 0.4896673567078327, 0.5108665222614683, 0.4518828919382324, 0.5140026275993831]

 

import matplotlib.pyplot as plt
plt.style.use('seaborn-white')

x=[int(i) for i in range(min_topics,max_topics)]

plt.figure(figsize=(10,5))
plt.plot(x,coherence_scores)
plt.xlabel('Number of Topics')
plt.ylabel('Coherence Scores')
plt.show()

잠재 디리클레 할당을 위한 LDA Model 그래프


4. 토픽 모델링 시각화

!pip install pyLDAvis
import pyLDAvis.gensim_models

pyLDAvis.enable_notebook()
vis=pyLDAvis.gensim_models.prepare(lda_model,corpus,dictionary)
pyLDAvis.display(vis)

 

'Study' 카테고리의 다른 글

[NLP] 8. 스팸 메일 분류  (0) 2024.08.25
[NLP] 7. Embedding  (0) 2024.08.21
[NLP] 5. Semantic Network Analysis  (0) 2024.08.20
[NLP] 4. Document Classification  (0) 2024.08.20
[NLP] 3. Cluster Analysis  (0) 2024.08.19