+ 개발

뉴스 데이터 LSA 분석(ft. Numpy & Scikit-learn)

AI.Logger 2024. 9. 13. 00:07
  • 수업 내용 리마인드 및 아카이빙 목적의 업로드


 

LSA(Latent Semantic Analysis)는 문서의 단어 간 숨겨진 의미를 분석하는 강력한 방법 중 하나입니다. 이번 글에서는 LSA를 활용해 간단한 실습을 진행하고, 뉴스 데이터를 분석하는 과정을 단계별로 살펴보겠습니다.

 

1. LSA 간단 실습

LSA는 문서-단어 행렬(DTM)을 특이값 분해(SVD)를 통해 분석하는 방법입니다. 이를 통해 문서 내에 존재하는 잠재적 의미를 추출할 수 있어요.

 

1) DTM 행렬 생성

먼저, 예시 데이터로 문서-단어 행렬(DTM)을 만들어봅니다.

import numpy as np

A = np.array([[0,0,0,1,0,1,1,0,0],
              [0,0,0,1,1,0,1,0,0],
              [0,1,1,0,2,0,0,0,0],
              [1,0,0,0,0,0,0,1,1]])
print('DTM의 크기(shape) :', np.shape(A))

이 행렬은 4개의 문서와 9개의 단어로 구성되어 있으며, 각 값은 단어가 문서에서 몇 번 등장했는지를 나타냅니다.

 

2) Full SVD

SVD를 통해 문서-단어 행렬을 분해합니다. SVD는 세 개의 행렬 U, S, VT로 분해되며, 이 행렬을 사용해 원본 행렬을 다시 근사할 수 있습니다.

U, s, VT = np.linalg.svd(A, full_matrices=True)
  • U는 문서와 관련된 행렬이고, VT는 단어와 관련된 행렬입니다.
  • S는 특이값 벡터로, 이를 대각 행렬로 변환해 다시 원본 행렬을 재구성할 수 있어요.

3) Truncated SVD

특이값 중 상위 2개만 보존해 차원을 축소한 SVD를 진행해봅니다. 이를 통해 차원을 축소하면서도 문서 간의 의미를 최대한 보존할 수 있죠.

S = S[:2,:2]
U = U[:,:2]
VT = VT[:2,:]
A_prime = np.dot(np.dot(U,S), VT)

이렇게 상위 특이값만을 사용해 근사한 행렬을 확인할 수 있습니다.

 

4) sklearn을 사용한 TruncatedSVD

더 간편하게 LSA를 구현하려면 Scikit-learn의 TruncatedSVD를 사용할 수 있습니다.

from sklearn.decomposition import TruncatedSVD

svd_model = TruncatedSVD(n_components=2, algorithm='randomized', random_state=42)
lsa_matrix = svd_model.fit_transform(A)

이 과정에서 문서-토픽 행렬단어-토픽 행렬을 얻을 수 있으며, 이를 통해 문서와 단어 간의 관계를 더 쉽게 분석할 수 있어요.

 

2. 뉴스 데이터를 활용한 LSA 분석

이번에는 실제 뉴스 데이터를 활용해 LSA를 적용해볼게요. Twenty Newsgroups 데이터는 사이킷런에서 제공하는 뉴스그룹 데이터로, 20개의 주제를 가진 뉴스 기사들로 구성되어 있습니다.

 

1) 데이터 로드 및 전처리

뉴스 데이터를 불러와 전처리를 진행합니다. 텍스트에서 특수 문자나 불필요한 단어들을 제거해 더 깔끔한 데이터를 만듭니다.

from sklearn.datasets import fetch_20newsgroups
import pandas as pd

dataset = fetch_20newsgroups(shuffle=True, random_state=1, remove=('headers', 'footers', 'quotes'))
documents = dataset.data
news_df = pd.DataFrame({'document':documents})

# 특수 문자 제거, 짧은 단어 제거, 소문자 변환
news_df['clean_doc'] = news_df['document'].str.replace("[^a-zA-Z]", " ", regex=True)
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: ' '.join([w for w in x.split() if len(w)>3]))
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: x.lower())

 

2) TF-IDF 벡터화

뉴스 기사를 TF-IDF로 벡터화합니다. 이 과정에서 상위 1,000개의 단어만을 보존하고, 너무 자주 등장하는 단어는 무시합니다.

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(stop_words='english', max_features=1000, max_df=0.5, smooth_idf=True)
X = vectorizer.fit_transform(news_df['clean_doc'])

 

3) LSA를 통한 토픽 모델링

LSA를 적용해 20개의 토픽을 추출합니다. 각 토픽에 대해 상위 단어를 확인해봅니다.

svd_model = TruncatedSVD(n_components=20, algorithm='randomized', n_iter=100, random_state=10)
svd_model.fit(X)

terms = vectorizer.get_feature_names_out()

# 각 토픽에서 중요한 단어 출력
for idx, topic in enumerate(svd_model.components_):
    sorted_indices = topic.argsort()[::-1][:5]
    print("Topic %d:" % (idx+1), [(terms[i], topic[i].round(5)) for i in sorted_indices])

 

4) 문서별 토픽 확인

각 문서가 어떤 토픽에 가장 큰 기여를 하는지 확인할 수 있습니다.

lsa_matrix = svd_model.transform(X)

def get_document_topics(lsa_matrix, n=5):
    for idx, doc in enumerate(lsa_matrix):
        if idx == 10: break
        print(f"Document {idx+1}:", [(f"Topic {i+1}", doc[i].round(5)) for i in doc.argsort()[::-1][:n]])

get_document_topics(lsa_matrix, n=5)

 

 

LSA(잠재 의미 분석)는 대규모 텍스트 데이터를 분석할 때 매우 유용한 기법입니다. 간단한 DTM 행렬을 통해 문서의 숨겨진 의미를 추출할 수 있고, 뉴스 데이터와 같은 실제 데이터를 분석할 때도 강력한 도구로 사용됩니다.

  • LSA를 통해 문서-단어 간의 관계를 분석하고, 문서들이 어떤 주제에 속해 있는지 파악할 수 있습니다.
  • TruncatedSVD를 활용하면 차원을 축소하면서도 중요한 정보를 보존해 문서 간 유사성을 분석할 수 있습니다.