[Python] 머신러닝 완벽가이드 - 08. 텍스트 분석[토픽 모델링]

Updated:

파이썬 머신러닝 완벽가이드 교재를 토대로 공부한 내용입니다.

실습과정에서 필요에 따라 내용의 누락 및 추가, 수정사항이 있습니다.


기본 세팅

import numpy as np
import pandas as pd

import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns

import warnings
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

mpl.rc('font', family='NanumGothic') # 폰트 설정
mpl.rc('axes', unicode_minus=False) # 유니코드에서 음수 부호 설정

# 차트 스타일 설정
sns.set(font="NanumGothic", rc={"axes.unicode_minus":False}, style='darkgrid')
plt.rc("figure", figsize=(10,8))

warnings.filterwarnings("ignore")

4. 토픽 모델링

텍스트 요약 기법인 토픽 모델링은 문서 집합에 숨어 있는 주제를 찾아내는 방법이다.

머신러닝 기반의 토픽 모델링은 주로 LSA(Latent Semantic Analysis)와 LDA(Latent Dirichlet Allocation)을 사용한다.

여기선 LDA 기반 토픽 모델링을 적용해본다(선형 판별 분석 LDA와 다름 유의).

from sklearn.datasets import fetch_20newsgroups

# 모토사이클, 야구, 그래픽스, 윈도우즈, 중동, 기독교, 전자공학, 의학 8개 주제 추출
cats = ['rec.motorcycles', 'rec.sport.baseball', 'comp.graphics', 'comp.windows.x',
        'talk.politics.mideast', 'soc.religion.christian', 'sci.electronics', 'sci.med'  ]

# 위에서 지정한 주제만 추출
news_df= fetch_20newsgroups(subset='all',remove=('headers', 'footers', 'quotes'), 
                            categories=cats, random_state=0)
  • 사이킷런 내부 데이터 20 뉴스그룹 데이터 셋에서 일부 주제의 기사만 추출하였다.
from sklearn.feature_extraction.text import CountVectorizer

# LDA는 CountVectorizer만 적용
count_vect = CountVectorizer(max_df=0.95, max_features=1000, min_df=2, stop_words='english', ngram_range=(1,2))
feat_vect = count_vect.fit_transform(news_df.data)

print('CountVectorizer Shape:', feat_vect.shape)
CountVectorizer Shape: (7862, 1000)
  • max_df로 빈도수가 95% 이내인 단어만 추출한다.

  • max_features로 피처의 갯수는 가장 높은 빈도를 가진 단어 순으로 1,000개 사용

  • min_df로 빈도수가 2 이하인 단어는 제외

  • LDA에서 피처 벡터화는 CountVectorizer만 사용한다.

from sklearn.decomposition import LatentDirichletAllocation

lda = LatentDirichletAllocation(n_components=8, random_state=0)
lda.fit(feat_vect)
LatentDirichletAllocation(n_components=8, random_state=0)
  • LDA에서 n_components로 토픽의 갯수를 조정한다.
lda.components_
array([[3.60992018e+01, 1.35626798e+02, 2.15751867e+01, ...,
        3.02911688e+01, 8.66830093e+01, 6.79285199e+01],
       [1.25199920e-01, 1.44401815e+01, 1.25045596e-01, ...,
        1.81506995e+02, 1.25097844e-01, 9.39593286e+01],
       [3.34762663e+02, 1.25176265e-01, 1.46743299e+02, ...,
        1.25105772e-01, 3.63689741e+01, 1.25025218e-01],
       ...,
       [3.60204965e+01, 2.08640688e+01, 4.29606813e+00, ...,
        1.45056650e+01, 8.33854413e+00, 1.55690009e+01],
       [1.25128711e-01, 1.25247756e-01, 1.25005143e-01, ...,
        9.17278769e+01, 1.25177668e-01, 3.74575887e+01],
       [5.49258690e+01, 4.47009532e+00, 9.88524814e+00, ...,
        4.87048440e+01, 1.25034678e-01, 1.25074632e-01]])
  • components_ 속성은 각 토픽별로 word 피처가 해당 토픽에 얼마나 할당됐는지 수치로 나타낸다.

  • 값이 클수록 해당 word 피처는 그 토픽의 중심 word가 된다.

print(lda.components_.shape)
(8, 1000)
  • 앞서 토픽의 갯수는 8, 피처의 수는 1,000개로 제한하여 8 x 1,000으로 나타났다.

  • 어떠한 피처가 연관성이 높은지 함수로 만들어 보자.

Word 피처명 추출 함수

def display_topics(model, feature_names, no_top_words):
    topic_news20 = ["모토사이클", "야구", "그래픽스", "윈도우즈", "중동", "기독교", "전자공학", "의학"]
    
    for topic_index, topic in enumerate(model.components_):
        print('Topic #', topic_index + 1, topic_news20[topic_index])

        # 각 토픽별 word 피처 연관도 내림차순 정렬시 값들의 index 반환 .. (1)
        topic_word_indexes = topic.argsort()[::-1] # [::-1] 역순으로 정렬
        top_indexes = topic_word_indexes[:no_top_words]
        
        # (1)의 index로 피처 이름명 추출
        feature_concat = '/'.join([feature_names[i] for i in top_indexes])                
        
        print(feature_concat)
        print(" ")
# CountVectorizer 객체의 전체 word 명칭
feature_names = count_vect.get_feature_names()

# Topic별 가장 연관도가 높은 word 15개
display_topics(lda, feature_names, 15)
Topic # 1 모토사이클
year/10/game/medical/health/team/12/20/disease/cancer/1993/games/years/patients/good
 
Topic # 2 야구
don/just/like/know/people/said/think/time/ve/didn/right/going/say/ll/way
 
Topic # 3 그래픽스
image/file/jpeg/program/gif/images/output/format/files/color/entry/00/use/bit/03
 
Topic # 4 윈도우즈
like/know/don/think/use/does/just/good/time/book/read/information/people/used/post
 
Topic # 5 중동
armenian/israel/armenians/jews/turkish/people/israeli/jewish/government/war/dos dos/turkey/arab/armenia/000
 
Topic # 6 기독교
edu/com/available/graphics/ftp/data/pub/motif/mail/widget/software/mit/information/version/sun
 
Topic # 7 전자공학
god/people/jesus/church/believe/christ/does/christian/say/think/christians/bible/faith/sin/life
 
Topic # 8 의학
use/dos/thanks/windows/using/window/does/display/help/like/problem/server/need/know/run
  • 벡터 객체의 get_feature_names()을 이용해 전체 word 피처 명칭을 알 수 있다.

  • 각 토픽별로 연관성이 높은 단어를 봤을 때 그래픽스는 image, jpeg등 관련 주제어가 잘 추출되었다.

  • 나머지에선 어느 정도 맞기도 하고 아니기도 하고 애매하다.

Leave a comment