Document-Term Matrix: 문서 여러 개를 하나의 행렬로 쌓는 법
DTM의 구조와 생성 과정, 희소 행렬 문제, TF-IDF·임베딩·차원 축소로 보완하는 방법과 실무 적용 사례를 정리한다.
2026-08-14 · 최초 발행 2025-05-23
BoW로 만든 벡터 하나는 문서 하나의 단어 빈도를 보여줄 뿐이다. 문서가 여러 개로 늘어나면 이 벡터들을 나란히 쌓아야 하는데, 그 결과물이 문서-단어 행렬(Document-Term Matrix, DTM)이다.
행과 열로 펼쳐놓은 단어 빈도
문서단어행렬(Document-Term Matrix, DTM)은 여러 문서에 등장하는 단어들의 출현 빈도를 행렬 형태로 표현한 데이터 구조다. 행(row)은 개별 문서를, 열(column)은 문서 집합(corpus)에 등장하는 고유 단어를 나타내고, 행렬의 각 셀은 해당 문서에서 특정 단어가 등장한 빈도(frequency)를 의미한다 — BoW를 여러 문서로 확장한 개념으로 이해할 수 있다.
DTM을 만드는 과정은 문서 수집, 전처리(토큰화·불용어(stop words) 제거·어간 추출(stemming) 또는 표제어 추출(lemmatization)을 통한 단어 정규화), 모든 문서에 등장하는 고유 단어를 추출해 사전을 구성하는 단어 사전 구축, 각 문서별 단어 빈도를 계산해 행렬에 배치하는 행렬 생성 순으로 이어진다.
예제 문장으로 보는 DTM
세 개의 간단한 문서가 있다고 하자.
문서 1: "데이터 분석은 중요하다." 문서 2: "데이터 과학은 통계를 활용한다." 문서 3: "분석은 패턴을 찾는 과정이다."
이를 DTM으로 표현하면 다음과 같다.
| 문서/단어 | 데이터 | 분석 | 중요하다 | 과학 | 통계 | 활용한다 | 패턴 | 찾는 | 과정이다 |
|---|---|---|---|---|---|---|---|---|---|
| 문서 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 문서 2 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
| 문서 3 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
코드로 만들어보는 DTM
from sklearn.feature_extraction.text import CountVectorizer
# 예시 문서
documents = [
"데이터 분석은 중요하다",
"데이터 과학은 통계를 활용한다",
"분석은 패턴을 찾는 과정이다"
]
# DTM 생성
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(documents)
# 특성 이름 확인
print("특성 이름:", vectorizer.get_feature_names_out())
# DTM 확인
print("DTM 형태:", X.shape)
print("DTM:\n", X.toarray())
DTM이 실제로 하는 일
DTM은 코사인 유사도·유클리드 거리 등을 활용한 문서 유사도 측정, 기계학습 알고리즘의 피처(feature)로 쓰는 문서 분류, 검색 시스템에서 문서 랭킹을 위한 정보 검색, LDA(Latent Dirichlet Allocation) 같은 알고리즘의 입력이 되는 토픽 모델링, 문서 집합을 유사한 그룹으로 묶는 텍스트 클러스터링에 쓰인다.
행렬이 커질수록 드러나는 문제들
첫째는 희소 표현(Sparse representation) 문제다. 실제 문서 집합에서는 단어 수가 매우 많지만 개별 문서에는 일부 단어만 등장하기 때문에 대부분의 값이 0인 희소 행렬(sparse matrix)이 만들어지고, 메모리 효율성이 떨어지고 계산 복잡성이 늘어난다.
희소 행렬 자료구조를 활용하거나, SVD·PCA 같은 차원 축소 기법을 적용하거나, 등장 빈도가 매우 낮거나 높은 단어를 제거하는 방식으로 대응한다.
둘째는 단순 빈도 수 기반 접근의 한계다. 단어의 의미적 중요도를 고려하지 않아 불용어나 자주 등장하는 단어가 분석 결과를 왜곡할 수 있고, 동의어·다의어 같은 단어의 문맥적 의미도 포착하지 못한다. TF-IDF 변환, 단어 임베딩(Word Embedding) 활용, 토픽 모델링 기법으로 보완한다.
가중치와 임베딩으로 보완하기
단순 빈도수가 아닌 단어의 상대적 중요도를 반영하려면 TF-IDF 변환을 적용한다. 문서 내 단어 빈도(TF)와 역문서 빈도(IDF)를 결합해, 문서 내에서는 빈번하게 등장하지만 다른 문서에서는 적게 등장하는 단어에 높은 가중치를 부여하는 방식이다.
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(documents)
print("TF-IDF 행렬:\n", tfidf_matrix.toarray())
Word2Vec·GloVe·FastText 같은 단어 임베딩 기법은 단어의 문맥적 의미를 고정 길이의 벡터로 표현해, 의미적으로 유사한 단어가 벡터 공간에서 가까운 위치에 매핑되도록 한다.
리뷰 분석부터 뉴스 추천까지
고객 리뷰 분석 시스템에서는 제품·서비스 리뷰를 DTM으로 변환해 주요 키워드를 추출하고, 긍정적·부정적 리뷰 그룹 간 단어 사용 패턴을 비교하며, 시간에 따른 키워드 트렌드 변화를 분석한다. 학술 논문 분류 시스템에서는 논문을 DTM으로 표현해 유사 연구를 클러스터링하고, 연구 분야별 핵심 용어를 분석하며, 새로운 논문의 분야를 자동으로 분류한다. 뉴스 기사 추천 시스템에서는 기사를 DTM으로 변환해 사용자가 읽은 기사와 유사한 기사를 추천하고, 특정 주제의 뉴스를 자동 분류하며, 시간에 따른 뉴스 토픽 변화를 추적한다.
큰 DTM을 다루는 법
PCA·LSA 등으로 고차원 DTM의 차원을 축소하고, SciPy의 sparse matrix로 메모리 효율을 높이며, 대용량 DTM은 Spark 같은 분산 처리 프레임워크로 처리하고, 전체 데이터를 한 번에 처리하지 않고 배치 단위로 처리하는 점진적 학습으로 성능을 최적화한다.
from scipy.sparse import csr_matrix
from sklearn.decomposition import TruncatedSVD
# 희소 행렬 변환
sparse_matrix = csr_matrix(X)
# LSA를 통한 차원 축소
lsa = TruncatedSVD(n_components=2)
lsa_result = lsa.fit_transform(sparse_matrix)
print("차원 축소 결과:", lsa_result)