짜리몽땅 매거진

[ML] 텍스트 벡터화하고 LDA 토픽모델링하기 본문

Data/Machine Learning

[ML] 텍스트 벡터화하고 LDA 토픽모델링하기

쿡국 2024. 10. 30. 15:06

정성데이터를 가공할 때, 텍스트 데이터에서 단어를 추출해야할 때 등 여러 케이스에서 자연어처리(NLP)를 해야하는 경우가 많다. 이때 초반에 진행해야하면서 기초적이지만 중요한 부분이 바로 '벡터화'이다. 

 

텍스트 벡터화는 텍스트 데이터를 수치 데이터로 변환하는 과정으로, 머신러닝 모델이 텍스트를 이해하고 처리할 수 있게 하는 중요한 단계이다. 그 중 가장 널리 알려진 Count Vectorizer와 TFIDF Vectorizer를 다루고자 한다.


1. Count Vectorizer

CountVectorizer는 텍스트 데이터에서 단어의 빈도를 세어 벡터로 변환하는 클래스이다.

from sklearn.feature_extraction.text import CountVectorizer

# 예시 리스트
corpus= [
    'This is the first corpus',
    'This corpus is the second corpus',
    'And this corpus is the third one',
    'Is this the first corpus?'
]

# CountVectorizer
cv=CountVectorizer()

# 문서 벡터화
X =cv.fit_transform(corpus)

# 변환 결과 출력
print('corpus 사용한 피처 : ',cv.get_feature_names_out())
print('----')
print('매트릭스 확인 : ',X.toarray())

2. TF-IDF Vectorizer

TfidfVectorizer는 단어의 빈도(TF)와 역문서 빈도(IDF)를 결합하여 단어의 중요도를 평가하는 클래스이다.

from sklearn.feature_extraction.text import TfidfVectorizer

# 예시 리스트
corpus= [
    'This is the first corpus',
    'This corpus is the second corpus',
    'And this corpus is the third one',
    'Is this the first corpus?'
]

# TFIDF 벡터화
vectorizer = TfidfVectorizer()

X=vectorizer.fit_transform(corpus)

# 변환 결과 출력
print('corpus 사용한 피처 :',vectorizer.get_feature_names_out())
print('----')
print('매트릭스 확인 :',X.toarray())


그렇다면 이제 벡터화된 데이터를 기반으로 유사도를 측정해 LDA(토픽모델링)까지 진행해보자.

 

유사도는 두 텍스트 데이터가 얼마나 비슷한지를 측정하는 값으로, 텍스트 간의 유사도를 계산하면 텍스트 분류, 정보 검색, 추천 시스템, 감성 분석 등에 활용할 수 있다. 그 중 가장 널리 쓰이는 코사인 유사도에 대해 살펴보자. 

 

코사인 유사도 (Cosine Similarity)는 두 벡터 간의 각도를 기반으로 유사도를 측정하는 방법으로, 벡터의 크기보다는 방향을 고려하여 계산하며, 값은 -1에서 1 사이의 범위를 가지는데, 텍스트 유사도에서 0~1 범위로 주로 사용된다.

 

LDA 토픽 모델링은 는 문서 내에 존재하는 단어들을 기반으로 잠재 주제(토픽)를 식별하는 모델이다. 각 문서는 여러 토픽의 혼합으로 구성되어 있다고 가정하고, 문서 내 단어 출현 빈도를 분석하여 특정 단어들이 어떤 토픽에 속할 확률이 높은지를 계산한다.

 

 

영화 리뷰 샘플 데이터셋을 활용해 벡터화부터 유사도 측정, 토픽모델링까지 실습해보자.

 

import pandas as pd

# 영화 리뷰 데이터 불러오기
df=pd.read_csv('movie_rv.csv')
df_sp=df.iloc[:50000]

import re 
from konlpy.tag import Okt

# Okt 형태소 분석기 생성
okt =Okt()

 

텍스트를 형태소 별로 처리하기 위해 Okt 형태소 분석기를 먼저 생성한다.

 

# 전처리 함수

def preprocess_text(text):
    #문자열 확인하고, 아니면 빈 문자열 반환
    if not isinstance(text,str):
        return ''
    #특수문자 제거
    text=re.sub(r'[^ㄱ-ㅎㅏ-ㅣ가-힣\s]','',text)
    #형태소로 분석을 통해 추출 (명사만 추출)
    nouns=okt.nouns(text)
    return ' '.join(nouns)

df_sp['document_cleand']=df_sp['document'].apply(preprocess_text)

print(df_sp[['document','document_cleand']])

 

이렇게 특수문자 제거, 명사 추출 등의 함수를 작성한 뒤, 전처리된 값을 확인하면 아래와 같다.

(좌) 전처리 전 document 데이터, (우) 전처리 후 document_cleaned 데이터

 

이제 앞서 배운 벡터화를 사용해 수치 데이터로 변환하고, 유사도를 측정해보자.

# CountVectorizer
cv=CountVectorizer()
X_cv_count=cv.fit_transform(df_sp['document_cleand'])

# tfidf
tfidf = TfidfVectorizer()
X_tfidf_count=tfidf.fit_transform(df_sp['document_cleand'])

# cosine_similarities
from sklearn.metrics.pairwise import cosine_similarity

cos_sim_count = cosine_similarity(X_cv_count)
cos_sim_tfidf = cosine_similarity(X_tfidf_count)

# 코사인 유사도를 통해 리뷰 10개 정도 추려서 리뷰와 코사인 유사도가 같은 Top3 리뷰를 출력

num_rvs = 10
for i in range(num_rvs):
    #cv
    simliar_indices_count = cos_sim_count[i].argsort()[::-1][1:11]
    similar_reviews_count = [(cos_sim_count[i][j], df_sp['document'][j]) for j in simliar_indices_count]
    
    #tfidf
    simliar_indices_tfidf = cos_sim_tfidf[i].argsort()[::-1][1:4]
    similar_reviews_tfidf = [(cos_sim_tfidf[i][j], df_sp['document'][j]) for j in simliar_indices_tfidf]
    
    print(f"\n Original Review {i+1}: {df_sp['document'][i]}")
    print("\n Top 3 similar reviews using countvectorizer:")
    for sim_score, reviews in similar_reviews_count:
        print(f"Similarity :{sim_score:.3f}, Reviews:{reviews}")
    
    print("\n Top 3 similar reviews using Tfidf:")
    for sim_score, reviews in similar_reviews_tfidf:
        print(f"Similarity :{sim_score:.3f}, Reviews:{reviews}")

유사도 측정 결과

 

from sklearn.decomposition import LatentDirichletAllocation

# LDA모델 학습
lda=LatentDirichletAllocation(n_components = 2, random_state=111)

lda.fit(X_cv_count)

# 상위 몇 개 단어를 가지고 올 것인가?
n_top_words = 10

def print_top_words(model, feature_name, n_top_words):
    for topic_idx, topic in enumerate(model.components_):
        print(f"Topic {topic_idx}:")
        print(" ".join([feature_name[i] for i in topic.argsort()[:-n_top_words-1:-1]]))
        
tf_feature_names=cv.get_feature_names_out()
print_top_words(lda, tf_feature_names, n_top_words)

토픽 결과 확인

 

이렇게 벡터화, 유사도 측정, 토픽모델링까지 진행했는데, 원하는 토픽 주제는 분석가 정할 수 있다. 위 예시에서는 2개의 토픽을 정하는데, 이 토픽은 어떤 특정 값이 아니라 계산해서 유사하다고 판단되는 토픽들을 묶어서 보여주는 것이다.

'Data > Machine Learning' 카테고리의 다른 글

[ML] 유저이탈 예측하기  (0) 2025.01.04
[ML] AutoML_TPOT으로 최적 모델 찾기  (1) 2024.10.29
[ML] Sweetviz와 Pipeline으로 모델링하기  (0) 2024.10.29
[ML] 데이터 샘플링  (0) 2024.10.25
[ML] 데이터 변환  (1) 2024.08.19