Skip to main content

텍스트 벡터화

학습 목표

  • 텍스트 벡터화(Text Vectorization)의 필요성과 역할을 설명할 수 있습니다
  • 희소 표현(BoW, TF-IDF)과 밀집 표현(Word2Vec, FastText, GloVe)의 차이를 비교할 수 있습니다
  • 각 벡터화 방법의 장단점과 적합한 사용 시나리오를 판단할 수 있습니다
  • sklearn과 gensim을 활용하여 텍스트 벡터화를 코드로 구현할 수 있습니다
  • 전통적 벡터화에서 딥러닝 임베딩으로의 발전 과정을 이해할 수 있습니다

왜 중요한가

컴퓨터는 텍스트를 직접 처리할 수 없습니다. 머신러닝 모델에 텍스트를 입력하려면 반드시 수치 벡터로 변환해야 합니다. 이 변환 과정을 벡터화(Vectorization) 또는 **임베딩(Embedding)**이라고 합니다. 벡터화 방법의 선택은 모델 성능에 직접적인 영향을 미칩니다. 단순한 빈도 기반(BoW)에서 문맥을 반영하는 밀집 임베딩(Word2Vec)으로의 발전은 NLP 성능을 크게 높였습니다. 이 역사적 발전을 이해하면 현대 Transformer 모델의 임베딩이 왜 강력한지도 자연스럽게 이해할 수 있습니다. 또한 RAG 시스템에서 사용되는 희소 검색(BM25)과 밀집 검색(Semantic Search)의 차이도 이 벡터화 개념에 기반합니다.

핵심 개념

벡터화 방법 비교 요약

방법유형차원문맥 반영의미 유사도주요 라이브러리
BoW희소어휘 크기 (수만~수십만)없음불가sklearn
TF-IDF희소어휘 크기없음제한적sklearn
Word2Vec밀집50~300주변 단어가능gensim
FastText밀집50~300주변 단어 + 서브워드가능 (OOV 포함)gensim, fasttext
GloVe밀집50~300전역 통계가능gensim (로드)

Bag of Words (BoW)

BoW는 가장 단순한 벡터화 방법입니다. 텍스트를 단어의 출현 횟수로 표현하며, 단어의 순서를 무시합니다.
from sklearn.feature_extraction.text import CountVectorizer

# 한국어 문서 (형태소 분석 후 공백으로 연결한 상태)
documents = [
    "자연어 처리 는 인공지능 의 핵심 기술 이다",
    "딥러닝 은 자연어 처리 에서 혁명 을 일으켰다",
    "인공지능 과 딥러닝 이 세상 을 바꾸고 있다"
]

# CountVectorizer로 BoW 벡터를 생성합니다
vectorizer = CountVectorizer()
bow_matrix = vectorizer.fit_transform(documents)

# 어휘 확인
print("어휘:", vectorizer.get_feature_names_out())
# ['과', '기술', '는', '딥러닝', '에서', '를', '세상', '이다', '인공지능', '은', ...]

# BoW 행렬 확인 (문서 × 어휘)
print(f"행렬 크기: {bow_matrix.shape}")
print("밀집 행렬:")
print(bow_matrix.toarray())
# 각 행은 문서, 각 열은 단어, 값은 출현 횟수입니다
BoW의 한계:
  • 단어 순서를 무시합니다. “개가 사람을 물었다”와 “사람이 개를 물었다”의 벡터가 비슷합니다.
  • 어휘 크기가 커지면 벡터 차원이 매우 커집니다 (고차원 희소 벡터).
  • 단어 간 의미적 관계를 포착하지 못합니다. “좋다”와 “훌륭하다”는 완전히 다른 차원입니다.

TF-IDF (Term Frequency-Inverse Document Frequency)

TF-IDF는 BoW를 개선하여, 특정 문서에서 중요한 단어에 높은 가중치를 부여합니다.
  • TF (Term Frequency): 해당 문서에서 단어가 등장한 횟수
  • IDF (Inverse Document Frequency): 전체 문서에서 해당 단어가 얼마나 드문지. 모든 문서에 나타나는 단어(“이다”, “는”)는 IDF가 낮습니다.
  • TF-IDF = TF × IDF: 특정 문서에서 자주 나타나면서 전체적으로는 드문 단어가 높은 점수를 받습니다.
from sklearn.feature_extraction.text import TfidfVectorizer

documents = [
    "자연어 처리 는 인공지능 의 핵심 기술 이다",
    "딥러닝 은 자연어 처리 에서 혁명 을 일으켰다",
    "인공지능 과 딥러닝 이 세상 을 바꾸고 있다"
]

# TF-IDF 벡터를 생성합니다
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(documents)

print(f"행렬 크기: {tfidf_matrix.shape}")

# 각 문서에서 가장 중요한 단어를 확인합니다
feature_names = tfidf_vectorizer.get_feature_names_out()
for i, doc in enumerate(documents):
    scores = tfidf_matrix[i].toarray().flatten()
    top_indices = scores.argsort()[-3:][::-1]  # 상위 3개
    top_words = [(feature_names[j], scores[j]) for j in top_indices]
    print(f"문서 {i+1} 핵심 단어: {top_words}")
# TF-IDF를 활용한 문서 유사도 계산
from sklearn.metrics.pairwise import cosine_similarity

# 문서 간 코사인 유사도를 계산합니다
similarity_matrix = cosine_similarity(tfidf_matrix)
print("문서 간 유사도:")
for i in range(len(documents)):
    for j in range(i+1, len(documents)):
        print(f"  문서 {i+1} ↔ 문서 {j+1}: {similarity_matrix[i][j]:.4f}")
TF-IDF는 RAG 시스템에서 BM25 알고리즘의 기반이 됩니다. BM25는 TF-IDF를 개선한 것으로, 문서 길이를 고려하고 TF의 포화 효과를 반영합니다. TF-IDF를 이해하면 RAG 탭에서 희소 검색의 원리를 쉽게 이해할 수 있습니다.

Word2Vec

Word2Vec은 단어를 저차원 밀집 벡터로 표현하는 방법입니다. 2013년 Google에서 발표되었으며, “유사한 맥락에서 등장하는 단어는 유사한 의미를 가진다”는 **분포 가설(Distributional Hypothesis)**에 기반합니다. 두 가지 학습 방식이 있습니다.
방식입력 → 예측특징
CBOW주변 단어 → 중심 단어빈번한 단어에 유리, 빠름
Skip-gram중심 단어 → 주변 단어드문 단어에 유리, 느리지만 정확
from gensim.models import Word2Vec

# 토큰화된 문장 리스트 (각 문장은 단어 리스트)
sentences = [
    ["자연어", "처리", "는", "인공지능", "의", "핵심", "기술", "이다"],
    ["딥러닝", "은", "자연어", "처리", "에서", "혁명", "을", "일으켰다"],
    ["기계", "학습", "은", "데이터", "에서", "패턴", "을", "학습", "한다"],
    ["인공지능", "은", "머신러닝", "과", "딥러닝", "을", "포함", "한다"],
    ["자연어", "처리", "에서", "토큰화", "는", "기본", "전처리", "이다"],
]

# Word2Vec 모델 학습
model = Word2Vec(
    sentences,
    vector_size=100,  # 벡터 차원 수
    window=5,         # 주변 단어 윈도우 크기
    min_count=1,      # 최소 등장 횟수
    sg=1,             # 1=Skip-gram, 0=CBOW
    epochs=100        # 학습 반복 횟수
)

# 단어 벡터 확인
vector = model.wv["자연어"]
print(f"'자연어' 벡터 (100차원): {vector[:5]}...")  # 처음 5개 값만 출력

# 유사 단어 검색
similar = model.wv.most_similar("자연어", topn=3)
print(f"'자연어'와 유사한 단어: {similar}")
# Word2Vec의 의미 연산 (큰 코퍼스에서 학습 시)
# "왕 - 남자 + 여자 ≈ 여왕" 과 같은 연산이 가능합니다
result = model.wv.most_similar(
    positive=["인공지능", "처리"],
    negative=["학습"],
    topn=3
)
print(f"인공지능 - 학습 + 처리 ≈ {result}")

# 단어 간 유사도 계산
similarity = model.wv.similarity("자연어", "인공지능")
print(f"'자연어' ↔ '인공지능' 유사도: {similarity:.4f}")

FastText

FastText는 Facebook(Meta)에서 개발한 모델로, Word2Vec을 개선하여 서브워드(Subword) 정보를 활용합니다. 단어를 문자 n-gram으로 분해하여 학습하므로, 학습 데이터에 없는 단어(OOV)도 벡터로 표현할 수 있습니다.
from gensim.models import FastText

# FastText 모델 학습
ft_model = FastText(
    sentences,
    vector_size=100,
    window=5,
    min_count=1,
    sg=1,
    epochs=100
)

# 학습 데이터에 없는 단어도 벡터를 생성할 수 있습니다 (OOV 처리)
# "자연어처리"는 학습 데이터에 없지만, "자연어"와 "처리"의 서브워드 정보로 벡터 생성
oov_vector = ft_model.wv["자연어처리"]
print(f"OOV 단어 '자연어처리' 벡터 생성 가능: {oov_vector[:5]}...")

# Word2Vec에서는 OOV 단어 조회 시 KeyError가 발생합니다
try:
    model.wv["자연어처리"]
except KeyError as e:
    print(f"Word2Vec OOV 에러: {e}")
특성Word2VecFastText
OOV 처리불가 (KeyError)가능 (서브워드 합성)
오타/변형인식 불가유사 벡터 생성
학습 속도빠름상대적으로 느림
모델 크기작음큼 (n-gram 저장)
형태소가 풍부한 언어보통유리 (한국어 등)

GloVe (Global Vectors)

GloVe는 Stanford에서 개발한 임베딩 방법으로, **전역 동시 등장 통계(Global Co-occurrence Statistics)**를 활용합니다. Word2Vec이 지역적 문맥 윈도우를 사용하는 반면, GloVe는 전체 코퍼스의 동시 등장 행렬을 분해하여 벡터를 학습합니다.
# GloVe는 별도 학습 도구를 사용하지만,
# 사전학습된 모델을 gensim으로 로드할 수 있습니다
import gensim.downloader as api

# 사전학습된 GloVe 모델 로드 (최초 실행 시 다운로드)
# glove_model = api.load("glove-wiki-gigaword-100")  # 100차원

# 로드 후 Word2Vec과 동일한 인터페이스로 사용합니다
# similar = glove_model.most_similar("computer", topn=5)
# print(similar)
# GloVe 텍스트 파일을 직접 로드하는 방법
import numpy as np

def load_glove(filepath, dim=100):
    """GloVe 텍스트 파일에서 임베딩을 로드합니다."""
    embeddings = {}
    with open(filepath, 'r', encoding='utf-8') as f:
        for line in f:
            values = line.strip().split()
            word = values[0]
            vector = np.array(values[1:], dtype='float32')
            if len(vector) == dim:
                embeddings[word] = vector
    print(f"로드된 단어 수: {len(embeddings)}")
    return embeddings

# 사용 예시 (파일이 있을 경우)
# embeddings = load_glove("glove.6B.100d.txt", dim=100)
# print(embeddings["computer"][:5])

벡터화 방법 선택 가이드

AI/ML에서의 활용

텍스트 벡터화는 NLP를 넘어 다양한 AI/ML 시스템에서 활용됩니다.
  • RAG 시스템: TF-IDF/BM25(희소 검색)와 밀집 임베딩(Dense Retrieval)은 RAG의 검색 엔진 핵심 기술입니다
  • 추천 시스템: 아이템 설명을 벡터화하여 콘텐츠 기반 추천에 활용합니다
  • 클러스터링: 문서 벡터를 기반으로 유사 문서를 그룹화합니다
  • 시각화: t-SNE, UMAP으로 단어/문서 벡터를 2D로 투영하여 관계를 시각화합니다
  • 전이 학습: 사전학습된 임베딩을 다른 태스크의 초기값으로 활용합니다
현대 Transformer 모델(BERT, GPT 등)은 **문맥 의존적 임베딩(Contextual Embedding)**을 생성합니다. 같은 단어도 문장에 따라 다른 벡터를 가집니다. Word2Vec, GloVe는 **정적 임베딩(Static Embedding)**으로, 문맥과 무관하게 단어마다 하나의 고정 벡터를 가집니다. Transformer의 임베딩은 Attention과 Transformer 그룹에서 자세히 다룹니다.
실무에서 큰 차이는 없습니다. Word2Vec은 지역적 문맥을, GloVe는 전역 통계를 활용하므로 이론적 차이는 있지만, 대규모 코퍼스에서 학습하면 비슷한 성능을 보입니다. 한국어의 경우 사전학습된 GloVe가 드물어서, Word2Vec이나 FastText를 직접 학습하는 경우가 많습니다.
세 가지 이유가 있습니다. 첫째, Word2Vec의 “분포 가설”과 “벡터 공간에서의 의미 연산” 개념은 Transformer 임베딩의 기반입니다. 둘째, 리소스가 제한된 환경에서 여전히 유용합니다. 셋째, RAG의 희소/밀집 검색 차이를 이해하려면 벡터화의 기본 개념이 필요합니다.
BM25는 TF-IDF의 개선 버전입니다. TF-IDF에서 TF 값이 단어 빈도에 비례하여 무한히 증가하는 반면, BM25는 포화 함수를 적용하여 특정 임계점 이상에서는 증가가 완만해집니다. 또한 문서 길이를 정규화하여 긴 문서가 불리하지 않게 합니다. RAG 탭에서 BM25를 자세히 다룹니다.
일반적으로 Word2Vec/FastText는 100~300차원을 사용합니다. 차원이 너무 작으면 정보 손실이 크고, 너무 크면 과적합과 계산 비용이 증가합니다. BERT는 768차원, GPT-3는 12,288차원을 사용합니다. 데이터 규모와 태스크 복잡도에 따라 조정하되, 사전학습 모델을 사용할 때는 모델의 기본 차원을 따릅니다.

체크리스트

  • 희소 표현(BoW, TF-IDF)과 밀집 표현(Word2Vec, FastText, GloVe)의 차이를 설명할 수 있다
  • TF-IDF의 TF, IDF 개념과 계산 방식을 이해한다
  • Word2Vec의 CBOW, Skip-gram 방식을 구분할 수 있다
  • FastText가 OOV 문제를 해결하는 원리를 설명할 수 있다
  • sklearn과 gensim으로 벡터화 코드를 작성할 수 있다
  • 정적 임베딩과 문맥 의존적 임베딩의 차이를 이해한다
  • 태스크와 데이터 특성에 따른 벡터화 방법을 선택할 수 있다

다음 문서