토픽 모델링
#
Find similar titles
-
최초 작성자
ybcho@d-if.kr
-
최근 업데이트
ybcho@d-if.kr
Structured data
- Category
- Big Data
- Image
Table of Contents
Topic modeling #
토픽 모델링(Topic Modeling), 혹은 주제 분석은 대규모의 텍스트 데이터에서 주요한 주제나 아이디어를 자동으로 식별하는 과정입니다. 이를 통해 수백, 수천, 수만 개의 문서에서 중요한 정보나 패턴을 빠르게 파악할 수 있습니다. 주제 분석은 뉴스 기사 분류, 고객 리뷰 분석, 연구 논문의 주제 판별 등 다양한 분야에 활용됩니다. 이 글에서는 자연어처리(Natural Language Processing) 분야에서 어떻게 텍스트를 표현하고, 이를 바탕으로 토픽 모델링이 이루어지는지를 살펴볼 예정입니다.
NLP에서의 텍스트 표현 방법 #
자연어 처리(Natural Language Processing)에서는 우리가 읽을 수 있는 언어를 컴퓨터가 읽을 수 있도록 변환하기 위해 다양한 방법들을 사용합니다. 이를 Word representation, 혹은 단어 표현이라고 하는데, 이러한 방법론도 각 단어를 어떻게 보느냐에 따라 단어 하나하나를 다르게 보는 국소표현 방식(Local Represenation)과 단어의 관계성에 집중하는 분산표현 방식(Distributed Representation), 혹은 연속표현 방식(Continuous Representation)으로 구분할 수 있습니다. 이번 주제인 토픽 모델링의 경우 단어 각각을 다르게 표현하는 방식이 중요하기 때문에 이산표현 방식을 사용하여 모델링을 진행합니다.
카운트 기반의 단어 표현 #
이산표현 방식을 이용한 모델링 방법에는 각 단어를 하나의 벡터로 각각 표현하는 one-hot vector 방식도 있지만, 주로 카운트 기반의 단어 표현(Count based word representation)을 많이 사용합니다. 카운트 기반의 단어 표현의 장점은 단어가 문서에서 얼마나 많이 등장하였는지를 기반으로 하였기 때문에 통계적인 접근 방법을 통해 단어의 특성을 구할 수 있다는 것입니다. 예를 들어 어떤 단어가 특정 문서에서 얼마나 중요한지를 표현할 때, 검색 엔진에서 검색 결과의 순위를 결정할 때, 문서 간의 유사도를 알고 싶을 때 사용할 수 있습니다. 이러한 카운트 기반의 단어 표현은 DTM(Document Term Matrix)라는 방식과 TF-IDF(Term Frequency-Inverse Document Frequency)라는 방식이 주로 활용됩니다.
DTM #
먼저 DTM에 대하여 알아보기 전에 빈도수 기반의 단어 표현 방법인 BoW(Bag of Words)라는 개념을 알아야 합니다. Bag of Words란 단어의 순서는 고려하지 않고, 단어의 출현 빈도(frequency)에 집중하는 수치화 표현 방법입니다. 가방에 단어들을 넣고 흔들어 섞었을 때 무작위로 추출하게 되면 순서와 상관없이 단어들이 뽑히게 됩니다. 이때 특정 단어가 나올 확률은 단어의 빈도수에 비례하게 될 겁니다. 이러한 개념을 바탕으로 등장한 BoW는 python에서 scikit-learn의 CountVectorizer라는 클래스를 통해 쉽게 만들 수 있습니다.
from sklearn.feature_extraction.text import CountVectorizer
corpus = ['you know I want your love. because I love you.']
vector = CountVectorizer()
# 코퍼스로부터 각 단어의 빈도수를 기록
print('bag of words vector :', vector.fit_transform(corpus).toarray())
# 각 단어의 인덱스가 어떻게 부여되었는지를 출력
print('vocabulary :',vector.vocabulary_)
# 결과
bag of words vector : [[1 1 2 1 2 1]]
vocabulary : {'you': 4, 'know': 1, 'want': 3, 'your': 5, 'love': 2, 'because': 0}
이제, 여러 개의 문서에서 해당 단어들을 표현하려면, 문서별로 해당 단어의 벡터들이 생성될 것입니다. 이렇게 만들어진 문서에서 단어의 빈도를 나타내는 행렬이 바로 문서 단어 행렬, DTM입니다. 단어들의 빈도를 표현하는 행렬을 간단히 구현하고자 한다면 이러한 DTM 방식이 좋습니다. 하지만 DTM은 서로 다른 단어들이 다른 문서에서 등장할 경우 대부분의 값이 0으로 표현될 수 있어 리소스 낭비가 심하며, 문장에서 자주 등장하는 관사나 조사 등의 표현이 자주 등장할 때 이게 자주 등장한다고 유사한 문서로 판단할 수 있다는 문제점이 있습니다.
TF-IDF #
이러한 문제점을 극복하기 위해 나온 방법이 생성한 DTM의 단어에 가중치를 부여하는 TF-IDF 방식입니다. 여기서 TF는 특정 문서 D에서 특정 단어 T가 등장하는 횟수를 의미하며, DF는 특정 단어T가 등장한 중복하지 않는 문서의 수를 의미합니다. 예를 들어, 문서 d1에서 ‘식품’이라는 단어가 25번, ‘컴퓨터’라는 단어가 75번, ‘사람’이라는 단어가 10번 등장하고, 문서 d2에서 ‘식품’이라는 단어가 50번, ‘컴퓨터’라는 단어가 50번 등장했다면
df(식품)= 2,df(사람)= 1
로 표시할 수 있습니다. 이때 IDF는 Inverse, 즉 역수를 의미하기 때문에 보통 전체 문서 수(n)에 대한 값에 로그를 취해 계산하게 되며, 계산식은
idf(t)=log(n/(1+df(t)))
가 됩니다. TF-IDF 역시 scikit-learn의 TfidfVEctorizer라는 클래스를 이용해서 쉽게 구현할 수 있습니다.
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
'you know I want your love',
'I like you',
'what should I do ',
]
tfidfv = TfidfVectorizer().fit(corpus)
print(tfidfv.transform(corpus).toarray())
print(tfidfv.vocabulary_)
# 결과
[[0. 0.46735098 0. 0.46735098 0. 0.46735098 0. 0.35543247 0.46735098]
[0. 0. 0.79596054 0. 0. 0. 0. 0.60534851 0. ]
[0.57735027 0. 0. 0. 0.57735027 0. 0.57735027 0. 0. ]]
{'you': 7, 'know': 1, 'want': 5, 'your': 8, 'love': 3, 'like': 2, 'what': 6, 'should': 4, 'do': 0}
이렇게 만든 단어의 벡터들을 활용해서 앞서 설명한 여러 가지 방법들인 토픽 모델링이나 문서 유사도의 계산 등에 활용할 수 있습니다.
Topic Modeling & NMF-LDA(with Code) #
앞서 말씀드린 것처럼 토픽 모델링(Topic Modeling)은 자연어 처리 분야에서 문서 집합에서의 ‘토픽’을 발견하기 위한 통계적 모델로, 텍스트 본문에 숨겨진 의미의 구조를 발견하기 위해 주로 사용하는 Text Mining 기법이라고 할 수 있습니다. 여기서 말하는 주제는 ‘특정 주제를 구성하는 단어들’을 의미합니다. 토픽 모델링은 주로 검색 엔진이나 고객 민원 시스템 등 문서의 주제를 알아내는 일이 중요한 곳에서 많이 활용됩니다. 토픽 모델링에 주로 사용하는 모델로는 LDA와 NMF, K-means 등의 방법들이 활용됩니다. 먼저 이 중에서 가장 많이 이용되는 LDA부터 알아보도록 하겠습니다.
LDA #
LDA(Latent Dirichlet Allocation), 혹은 잠재 디리클레 할당 모델은 문서 집합에서 특정 n개의 토픽을 지정하게 되면 문서에 대한 토픽의 분포와 각 토픽에서 특정 단어가 이루는 분포를 추정하는 모델입니다. LDA는 세 가지 가정을 통해 이루어집니다.
- 각 문서는 여러 개의 주제를 가질 수 있으며, 한 문서는 특정 주제를 얼마나 포함하는지의 확률 벡터로 표현된다.
- 하나의 토픽은 해당 토픽에서 이용되는 단어의 비율로 표현된다.
- 한 문서에서 특정 단어들이 등장할 가능성은 문서의 토픽 확률분포와 토픽의 단어 확률분포의 곱으로 표현된다.
이때, t를 토픽, d를 문서, w를 단어라고 할 때 문서에서 토픽의 확률 벡터를 P(t│d), 토픽에서 단어의 확률 벡터를 P(w|t)라고 한다면, 문서에서 특정 단어들이 등장할 가능성 P(w,d)는 아래와 같이 표현될 수 있습니다.
$$P(w,d)=C × \sum_{w_j∈w} {n^{w_j,d}} \prod_{i} {P(w_j |t_i)×P(t_i |d)}$$
해당 알고리즘의 경우 python scikit-learn의 LatentDirichletAllocation 클래스를 통해 구현할 수 있습니다. 해당 클래스를 이용하기 위해서는 앞서 설명한 DFM를 만드는 방법과 TF-IDF 방식을 이용한 벡터화를 진행한 후, 해당 데이터를 이용해 모델링을 진행합니다.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import pandas as pd
# Prepare text data preprocessed and set number of topics
text_data = pd.read_csv(“processed_file.csv”, encoding=’utf-8-sig’)
n_topics = 5
# Vectorize texts
vectorizer = TfidfVectorizer(max_df=0.95, min_df=2, stop_words='english')
vectorized_data = vectorizer.fit_transform(text_data)
# modeling
model = LatentDirichletAllocation(n_components=n_topics, random_state=0)
model.fit(vectorized_data)
NMF #
NMF에 대한 자세한 설명은 NMF 페이지를 참고해주세요. 해당 페이지에서는 코드만 작성하도록 하겠습니다.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import NMF
import pandas as pd
# Prepare text data preprocessed and set number of topics
text_data = pd.read_csv(“processed_file.csv”, encoding=’utf-8-sig’)
n_topics = 5
# Vectorize texts
vectorizer = TfidfVectorizer(max_df=0.95, min_df=2, stop_words='english')
vectorized_data = vectorizer.fit_transform(text_data)
# modeling
model = NMF(n_components=n_topics, random_state=0)
model.fit(vectorized_data)
Reference #
- https://wikidocs.net/book/2155 : 안상준, 유원준, 딥 러닝을 이용한 자연어 처리 입문
- https://lovit.github.io/nlp/2019/06/10/visualize_topic_models_with_pyldavis/ : NMF, k-means 를 이용한 토픽 모델링과 NMF, k-means + PyLDAvis 시각화