텍스트 분석이란?
이전 내용
토픽 모델링(Topic Modeling)
◆ 토픽 모델링:
문서 집합에 숨어 있는 주제를 찾아내는 것. 많은 양의 문서가 있을 때 머신러닝 기반의 토픽 모델링을 적용해 숨어 있는 중요 주제를 효과적으로 찾아낼 수 있다. 사람이 수행하는 토픽 모델링은 더 함축적인 의미로 문장을 요약하는 것에 반해, 머신러닝 기반의 토픽 모델은 숨겨진 주제를 효과적으로 표현할 수 있는 중심 단어를 함축적으로 추출한다.
머신러닝 기반의 토픽 모델링에 자주 사용되는 기법은 LSA(Latent Semantic Analysis)와 LDA(Latent Dirichlet Allocation)이다.
[LSA와 LDA]
LDA(Latent Dirichlet Allocation)와 LSA(Latent Semantic Analysis)는 토픽 모델링(Topic Modeling) 기법으로, 텍스트 데이터에서 주제를 자동으로 추출하는 데 사용된다. 둘 다 비슷한 목표를 가지고 있지만, 접근 방식과 작동 방식에서 차이가 있다.
LSA (Latent Semantic Analysis)
- 원리: LSA는 문서-단어 행렬(Document-Term Matrix, DTM)을 사용해 단어들 간의 관계를 수학적으로 분석하여 주요한 의미의 축을 찾으며, 이를 위해 특이값 분해(Singular Value Decomposition, SVD) 기법을 사용해 차원을 축소한다.
- 특징: DTM의 차원을 줄이면서 의미가 비슷한 단어들을 같은 주제로 묶습니다. 다만, 단어의 순서에는 신경 쓰지 않아 문장 구조를 고려하지 않는다.
LDA (Latent Dirichlet Allocation)
- 원리: LDA는 확률 모델로, 문서가 특정 토픽에 속할 확률과 단어가 특정 토픽에 존재할 확률을 추정하여 각 단어에 랜덤하게 주제를 할당한다. 주제가 단어와 문서에 배포되는 확률 분포를 기반으로 반복해서 갱신한다.
- 특징: LDA는 확률적 토픽 모델링을 통해 더 유연하게 주제를 할당할 수 있으며, 새 문서가 등장해도 유사한 주제 구조를 활용할 수 있다. 또한, 단어의 순서에 크게 구애받지 않는다.
비교 요약
구분 | LSA | LDA |
기법 | SVD 기반 차원 축소 | 확률적 토픽 모델 |
장점 | 해석이 간단하고 직관적 | 확률 분포를 통해 유연하게 토픽 할당 |
단점 | 단어 순서 무시, 해석이 딱딱할 수 있음 | 확률 계산 복잡성 증가, 초기 설정에 영향 받을 수 있음 |
응용 분야 | 텍스트 요약, 검색 최적화 | 토픽 분류, 문서 군집화 |
20 뉴스그룹 데이터 세트에 토픽 모델링 적용
20 뉴스그룹은 20가지의 주제를 가진 뉴스그룹의 데이터를 가지고 있는데,이 중 모터사이클, 야구, 그래픽스, 윈도우, 중동, 기독교, 전자공학, 의학의 8개 주제를 추출하고 이들 텍스트에 LDA 기반의 토픽 모델링을 적용해 본다.
사이킷런은 LDA 기반의 토픽 모델링을 LatentDirichletAllocation 클래스로 제공하는데, 사이킷런 초기 버전에는 LDA 토픽 모델링을 제공하지 않았으나 gensim과 같은 토픽 모델링 패키지가 인기를 끌면서 사이킷런도 LDA를 제공하게 되었다.
[필요한 주제 필터링 및 Count 기반 벡터화]
LDA 토픽 모델링을 위해 fetch_20newsgroups() API는 categories 파라미터를 통해 필요한 주제만 필터링해 추출하고 추출된 텍스트를 Count 기반으로 벡터화 변환한다.
max_features=1000 으로 word 피처의 개수를 제한하고, ngram_range(1,2)로 설정한다.
※ LDA는 Count 기반의 벡터화만 사용한다.
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
# 모터사이클, 야구, 그래픽스, 윈도우, 중동, 기독교, 전자공학, 의학 8개 주제 추출
cats = ['rec.motorcycles', 'rec.sport.baseball', 'comp.graphics', 'comp.windows.x',
'talk.politics.mideast', 'soc.religion.christian', 'sci.electronics', 'sci.med']
# 위에서 cats 변수로기재된 카테고리만 추출
news_df = fetch_20newsgroups(subset='all', remove=('headers', 'footers', 'quotes'),
categories=cats, random_state=0)
# LDA는 Count 기반의 벡터화만 적용
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 객체 변수인 feat_vect 모두 7862개 문서가 1000개의 피처로 구성된 행렬 데이터 이다.
[피처 벡터화된 데이터 세트를 기반으로 LDA 토픽 모델링 수행]
토픽의 개수는 위의 뉴스그룹에서 추출한 주제와 동일한 8개로 정한다.
LatentDirichletAllocation 클래스의 n_components 파라미터를 이용해 이 토픽 개수를 조정한다.
(random_state 값은 예제를 수행할 때마다 결과가 똑같게 하기 위해 입력)
lda = LatentDirichletAllocation(n_components=8, random_state=0)
lda.fit(feat_vect)
▶ LatentDirichletAllocation.fit(데이터 세트)을 수행하면 LatentDirichletAllocation 객체는 components_ 속성값을 가지게 되며, components_ 는 개별 토픽별로 각 word 피처가 얼마나 많이 그 토픽에 할당됐는지에 대한 수치를 가지고 있다.
높은 값일수록 해당 word 피처는 중심 word가 된다.
[components_ 의 형태와 속성값 확인]
print(lda.components_.shape)
lda.components_
▶ components_ 는 array[8, 1000] 으로 구성돼 있는데, 8개의 토픽별로 1000개의 word 피처가 해당 토픽별로 연관도 값을 가지고 있다. 즉, components_ array의 0번째 row, 10번째 col에 있는 값은 Topic #0에 대해서 피처 벡터화된 행렬에서 10번째 칼럼에 해당하는 피처가 Topic #0에 연관되는 수치 값을 가지고 있다.
[연관도가 높은 순으로 Word 나열]
lda_model.components_ 값만으로는 각 토픽별 word 연관도를 보기가 어려우므로, display_topics() 함수를 만들어 각 토픽별로 연관도가 높은 순으로 Word를 나열해 본다.
※ 하단은 오류 코드 입니다.
def display_topics(model, feature_names, no_top_words):
for topic_index, topic in enumerate(model.components_):
print('Topic #', topic_index)
# components_ array 에서 가장 값이 큰 순으로 정렬했을 때, 그 값의 array 인덱스 반환
topic_word_indexes = topic.argsort()[::-1]
top_indexes=topic_word_indexes[:no_top_words]
# top_indexes 대상인 인덱스별로 feature_names 에 해당하는 word feature 추출 후 join으로 concat
feature_concat = ' '.join([feature_names[i] for i in top_indexes])
print(feature_concat)
# CountVectorizer 객체 내의 전체 word의 명칭을 get_features_names() 를 통해 추출
feature_names = count_vect.get_feature_names()
# 토픽별 가장 연관도가 높은 word를 15개만 추출
display_topics(lda, feature_names, 15)
상단의 코드로 입력했을 때, 하단의 에러 메시지를 받는다.
AttributeError: 'CountVectorizer' object has no attribute 'get_feature_names'
이 에러는 최신 버전의 scikit-learn에서 발생하는데, 이는 CountVectorizer의 get_feature_names() 메서드가 get_feature_names_out()으로 변경되었기 때문이다. 따라서,
get_feature_names() → get_feature_names_out() 으로 수정해주면 된다.
※ 정정 코드
def display_topics(model, feature_names, no_top_words):
for topic_index, topic in enumerate(model.components_):
print('Topic #', topic_index)
# components_ array 에서 가장 값이 큰 순으로 정렬했을 때, 그 값의 array 인덱스 반환
topic_word_indexes = topic.argsort()[::-1]
top_indexes=topic_word_indexes[:no_top_words]
# top_indexes 대상인 인덱스별로 feature_names 에 해당하는 word feature 추출 후 join으로 concat
feature_concat = ' '.join([feature_names[i] for i in top_indexes])
print(feature_concat)
# CountVectorizer 객체 내의 전체 word의 명칭을 get_features_names_out() 를 통해 추출
# get_features_names 가 get_features_names_out() 로 변경됨
feature_names = count_vect.get_feature_names_out()
# 토픽별 가장 연관도가 높은 word를 15개만 추출
display_topics(lda, feature_names, 15)
Topic #0: 일부 불분명한 주제어들이 있으나, 주로 의학에 관련된 주제어 추출.
Topic #1: 명확하지 않고 일반적인 단어가 주를 이루고 있다.
Topic #2: 컴퓨터 그래픽스 영역의 주제어 다수 포함
Topic #3: 일반적인 단어로 주제어 추출
Topic #4: 명확하게 중동 영역의 주제어 추출
Topic #5: 일부 컴퓨터 그래픽스 영역의 주제어름 포함하고 있으나, 전반적인 컴퓨터 관련 용어들을 가지고 있음. (8개 토픽 중 하나로 매핑하기는 어렵다)
Topic #6: 명확하게 기독교 관련 주제어 추출
Topic #7: 윈도우 운영체제와 관련된 주제어 추출
다음 내용
[출처]
파이썬 머신러닝 완벽 가이드
codong.tistory.com - 자연어처리 입문: 토픽 모델링
heeya-stupidbutstudying.tistory.com - 토픽 모델링(LSA와 LDA)
bab2min.tistory.com - 토픽 모델링과 LSA, LDA 관계
coco0414.tistory.com - 토픽 모델링 LSA, LDA
velog.io - Topic modeling(LSA, LDA)
ratsgo's blog for textmining
'[파이썬 Projects] > <파이썬 머신러닝>' 카테고리의 다른 글
[머신러닝] 텍스트 분석: 문서 유사도 (6) | 2024.10.31 |
---|---|
[머신러닝] 텍스트 분석: 문서 군집화 (2) | 2024.10.31 |
[머신러닝] 텍스트 분석: 감성 분석 (3) | 2024.10.30 |
[머신러닝] 텍스트 분석: 분류 실습 (0) | 2024.10.30 |
[머신러닝] 텍스트 분석: BOW(Bag of Words) (1) | 2024.10.30 |