[LDA] Latent Dirichlet Allocation 활용 (Jupyter Notebook)
텍스트 데이터를 학습하는 기법 중에 토픽 모델링이 있다.
토픽 모델링 중에서도 LDA를 이용한 프로젝트이다.
LDA는 쉽게말하면 수많은 문서들에 쓰인 단어들을 이용해 모델을 학습시키는데
이 학습된 모델에 문서 하나를 Input 하면
이 문서가 어떤 TOPIC들로 이루어져있는지, 그 TOPIC들이 문서를 구성하는 크기(빈도)는 어떻게 되는지 알 수 있다.
데이터로는 공훈전자사료관에서 제공하는 독립유공자공적조서를 활용한다.
https://e-gonghun.mpva.go.kr/user/RewardOpenAPI.do?goTocode=50001
출처: https://joyhong.tistory.com/138#topic=0&lambda=1&term= [옳은 길로..]
import pandas as pd
csv = pd.read_csv('historical_records.csv')
LDA 분석을 위해선 형태소 분석이 필요하다. 15924명의 독립유공자에 관한 설명(description)을 형태소 분석한다.
import re
import gensim
from konlpy.tag import Okt
from tqdm import tqdm
from gensim import corpora
import matplotlib.pyplot as plt
def clean_text(text):
""" 한글, 영문, 숫자만 남기고 제거한다. :param text: :return: """
text = text.replace(".", " ").strip()
text = text.replace("·", " ").strip()
pattern = '[^ ㄱ-ㅣ가-힣|0-9|a-zA-Z]+'
text = re.sub(pattern=pattern, repl='', string=text)
return text
def tokenize(df):
okt = Okt()
df = clean_text(df)
return okt.nouns(df)
sentences = list(csv['description'])
dataset =[]
for i in tqdm(range(len(sentences)-1)):
news_content = sentences[i]
words = tokenize(news_content)
temp_arr =[]
for word in words:
if len(word) >1:
temp_arr.append(word)
dataset.append(temp_arr)
print(dataset)
len(dataset) #15924
#dataset 에는 각 유공자에 관한 설명에 쓰인 단어들이 들어가있다. (15924명이므로 dataset의 길이도 15924)
본격적인 토픽 모델링에 앞서, 우리는 이 단어들을 몇 개의 TOPIC으로 추려낼 지를 정해야한다.
즉, 주어진 데이터로 뽑아낼 수 있는 최적의 TOPIC 개수를 먼저 파악해야한다.
def perplexity(dataset):
dictionary = corpora.Dictionary(dataset)
corpus = [dictionary.doc2bow(text) for text in dataset]
coherence_arr = []
start = 2
limit = 40
step = 6
for i in range(start,limit,step):
ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = i, id2word=dictionary,passes=10, random_state=2053)
coherence_model_lda = gensim.models.CoherenceModel(model=ldamodel, texts=dataset, dictionary=dictionary, topn=10)
coherence = coherence_model_lda.get_coherence()
coherence_arr.append(coherence)
return coherence_arr
dictionary = corpora.Dictionary(dataset)
dictionary.filter_extremes(no_below=10, no_above=0.5)
corpus = [dictionary.doc2bow(text) for text in dataset]
coherence_arr = perplexity(dataset);
NUM_TOPICS = coherence_arr[coherence_arr['Coherence'] == coherence_arr['Coherence'].max()]['TOPIC_NO']
plt.plot(range(start,limit,step),coherence_arr)
dictionary = corpora.Dictionary(dataset)
dictionary.filter_extremes(no_below=10, no_above=0.5)
특정 비율 이상으로 너무 많이 쓰이거나 (no_above) 특정 개수 이하로 너무 적게 쓰인 (no_below) 단어는 삭제한다.
corpus = [dictionary.doc2bow(text) for text in dataset]
corpus
corpus란 말뭉치란 뜻으로, 단어를 ID로 매칭시킴과 동시에 그 개수를 담고 있는 list이다.
start = 2
limit = 40
step = 6
for i in range(start,limit,step):
ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = i, id2word=dictionary,passes=10, random_state=2053)
coherence_model_lda = gensim.models.CoherenceModel(model=ldamodel, texts=dataset, dictionary=dictionary, topn=10)
coherence = coherence_model_lda.get_coherence()
coherence_arr.append(coherence)
TOPIC 개수를 2로 지정하고 LDA 모델을 학습시킨 후 만들어진 모델의 Coherence를 계산한다. Coherence가 높을수록 합리적인 모델이다.
2개부터 40개까지 하나하나 보면 시간이 너무 오래걸리므로 step을 6개로 두고 건너뛰어가며 Coherence를 계산한다.
두번째 step, 즉 TOPIC의 개수가 8개에서 가장 높은 Coherence가 나왔으므로 주어진 데이터에서 최적의 TOPIC 개수는 8개이다. (어떻게 전처리하냐에 따라 달라짐)
ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = 8, id2word=dictionary,passes=50, random_state=2053)
ldamodel.save("study_LDA.model")
top_words_per_topic = []
for t in tqdm(range(ldamodel.num_topics)):
top_words_per_topic.extend([(t, ) + x for x in ldamodel.show_topic(t, topn = 50)])
top_words_per_topic
TOPIC을 구성하는 단어와 빈도를 확인하려했으나 너무 보기가 힘들었다.
pyLDAvis 라이브러리를 통해 시각화를 하자.
import pyLDAvis
import pyLDAvis.gensim_models as gensimvis
lda_visualization = gensimvis.prepare(ldamodel,corpus,dictionary, mds = 'mmds')
df1 = pd.DataFrame(lda_visualization[0],columns=['x','y','topics','cluster','Freq'])
df1.to_csv('lda_visu_study.csv')
html으로도 시각화가 가능하다. (훨씬 보기편하고 뭔가 해낸거같음,, 사실은 별거없는데,,)
pyLDAvis.show(lda_visualization)
이렇게하면 알아서 로컬 서버가 띄워지면서 html을 그려주지만 이런 저런 오류가 너무 많이떠서 포기했다.
다행히 html을 따로 제공해주는 메소드가 있으므로 flask를 이용하여 직접 서버를 띄워서 html를 렌더링하기로 했다.
먼저 templates라는 이름을 가진 새 폴더 하나를 만들어준다. flask의 render_html 메소드를 사용할 때 이렇게 해야된단다.. ( 왜인지는 나중에 알아보기로 )
그 후 save_html 메소드를 통해 해당 폴더에 html을 저장해준다.
pyLDAvis.save_html(lda_visualization, './templates/pyldavis_html.html')
그럼 뾰로롱 하고 html 파일이 생긴다!
이제 서버를 띄워 렌더링만 해주자.
import webbrowser
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def hello():
return render_template('pyldavis_html.html')
webbrowser.open('http://127.0.0.1:5000')
if __name__ == "__main__":
app.run()
LDA 모델을 구성하는 8개의 토픽과, 각각의 TOPIC을 구성하는 단어들이 들어가있다.
오른쪽 그래프를 예로 설명하자면,
1번 토픽을 구성하는 단어들은 만세,독립,시위 등등이다.
하늘색 막대그래프는 단어가 총 문서에서 차지하는 개수이고
빨강색 막대그래프는 1번 토픽을 구성하는 단어의 개수다.
이제 저 완성된 LDA모델을 활용하는 방법은 댓글로 물어보시거나 API를 참고하기 바란다.
https://radimrehurek.com/gensim/apiref.html
Gensim: topic modelling for humans
Efficient topic modelling in Python
radimrehurek.com