Bag of Words: 단어 순서를 버리고 빈도만 세는 이유

BoW가 문서를 벡터로 바꾸는 절차와 장단점, TF-IDF·N-gram·Word Embeddings로 이어지는 확장, 금융·고객서비스 적용 코드를 정리한다.

2026-08-14 · 최초 발행 2025-05-23

문서를 하나의 '가방'에 쏟아붓고 단어가 몇 번 나왔는지만 세면 어떻게 될까 — Bag of Words(BoW)는 이 질문 하나에서 출발한 텍스트 벡터화 방법이다. 단어의 출현 빈도(frequency)에 기반해 텍스트를 벡터로 변환하며, 등장 순서는 고려하지 않는다.

BoW가 무시하는 것과 남기는 것

BoW는 문서를 단어들의 '가방(bag)'으로 간주해 단어의 위치나 순서를 무시하고 오직 출현 빈도만 계산한다. 단어의 시맨틱(의미) 관계나 문법적 구조는 고려하지 않으며, 벡터의 차원은 전체 어휘 집합(vocabulary)의 크기만큼 늘어난다. 문서 분류, 감성 분석, 문서 유사도 계산, 스팸 필터링 등에 쓰인다.

문장 하나가 벡터가 되기까지

BoW 모델을 구축하는 과정은 토큰화(Tokenization)로 문서를 단어·토큰으로 분리하고, 모든 고유 단어에 인덱스를 할당하는 어휘 집합을 만든 다음, 각 문서를 벡터로 변환해 인덱스 위치마다 해당 단어의 등장 빈도를 채워 넣는 순서로 진행된다.

텍스트 문서토큰화어휘 집합 생성인덱스 할당빈도수 계산벡터 생성

예를 들어 "정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다."라는 문장이 있다고 하자.

문장을 단어 단위로 분리하면 ["정부", "가", "발표", "하는", "물가상승률", "과", "소비자", "가", "느끼는", "물가상승률", "은", "다르다"]가 된다. 여기서 고유한 단어들을 추출해 인덱스를 부여하면 다음과 같다.

{
  '정부': 0,
  '가': 1,
  '발표': 2,
  '하는': 3,
  '물가상승률': 4,
  '과': 5,
  '소비자': 6,
  '느끼는': 7,
  '은': 8,
  '다르다': 9
}

각 단어의 출현 빈도를 기록한 벡터는 [1, 2, 1, 1, 2, 1, 1, 1, 1, 1]이다 — '정부'는 1번, '가'는 2번, '발표'는 1번, '물가상승률'은 2번 등장한 결과가 그대로 벡터에 반영된다.

코드로 확인하는 BoW 벡터

from sklearn.feature_extraction.text import CountVectorizer

# 예시 문서
documents = [
    "정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다.",
    "소비자는 주로 식품과 에너지 가격 상승을 체감한다."
]

# CountVectorizer 객체 생성
vectorizer = CountVectorizer()

# BoW 모델 학습 및 변환
X = vectorizer.fit_transform(documents)

# 어휘 집합 확인
print("어휘 집합:", vectorizer.get_feature_names_out())

# BoW 벡터 확인
print("BoW 벡터:\n", X.toarray())

BoW의 득과 실

장점은 복잡한 알고리즘 없이 직관적으로 구현할 수 있고, 벡터 연산이 빠르고 효율적이며, 문서 분류와 클러스터링에서 효과적인 성능을 내고, 결과물을 이해하기 쉽다는 점이다.

단점도 뚜렷하다. 단어 순서를 무시하기 때문에 "고양이가 쥐를 쫓는다"와 "쥐가 고양이를 쫓는다"가 동일한 BoW 벡터가 되어 문장의 의미와 맥락을 완전히 포착하지 못한다. 대부분의 값이 0인 고차원 희소 벡터(Sparsity)가 만들어지고, 자주 등장하는 불용어(stopwords)가 과도하게 강조되어 단어 중요도를 제대로 반영하지 못하며, 훈련 데이터에 없는 새로운 단어가 등장하면 처리하기 어렵다.

BoW 다음에 오는 것들

BoW의 한계를 보완하는 방향은 세 갈래다.

TF-IDF는 단순 빈도수가 아닌 단어의 중요도를 반영하는 가중치 부여 방식이다.

단어 빈도 TFTF-IDF역문서 빈도 IDF가중치가 적용된 벡터

N-gram 모델은 연속된 N개의 단어를 하나의 토큰으로 처리해 문맥 정보를 일부 보존한다.

유니그램(1-gram): ["정부", "가", "발표", ...]
바이그램(2-gram): ["정부가", "가발표", "발표하는", ...]
트라이그램(3-gram): ["정부가발표", "가발표하는", ...]

Word Embeddings는 단어를 의미적 관계가 보존되는 밀집 벡터(dense vector)로 표현하는 방식으로, Word2Vec·GloVe·FastText 같은 방법론이 있다.

뉴스 분류부터 이상 탐지까지

텍스트 분류에서는 뉴스 기사 카테고리 분류, 스팸 메일 필터링, 감성 분석(긍정/부정 분류)에 쓰인다. 정보 검색에서는 문서 유사도 계산과 검색 엔진의 문서 랭킹에 활용된다. 추천 시스템에서는 콘텐츠 기반 필터링과 사용자 리뷰 분석에 쓰이고, 이상 탐지에서는 비정상적인 텍스트 패턴 감지와 사기 감지 시스템에 활용된다.

금융 뉴스와 민원 분류에 적용해보면

금융 분야에서는 뉴스의 감성을 분석해 주가를 예측하는 데 BoW를 활용할 수 있다.

# 금융 뉴스 감성 분석 예시
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB

# 학습 데이터
news_data = [
    "기업 실적 상승으로 주가 상승 전망",
    "경기 침체 우려로 투자심리 위축",
    # ... 더 많은 뉴스 데이터
]
labels = [1, 0]  # 1: 긍정, 0: 부정

# BoW 모델 생성
vectorizer = CountVectorizer()
X_train = vectorizer.fit_transform(news_data)

# 분류기 학습
classifier = MultinomialNB()
classifier.fit(X_train, labels)

# 새로운 뉴스 분류
new_news = ["신제품 출시로 매출 증가 예상"]
X_new = vectorizer.transform(new_news)
prediction = classifier.predict(X_new)
print("뉴스 감성:", "긍정" if prediction[0] == 1 else "부정")

고객 서비스에서는 민원을 자동으로 분류하는 시스템에도 같은 방식을 적용할 수 있다.

# 민원 자동 분류 예시
complaints = [
    "제품이 작동하지 않습니다. 환불해주세요.",
    "배송이 지연되고 있어요. 언제 도착하나요?",
    "앱이 자꾸 충돌해서 사용할 수 없어요.",
    # ... 더 많은 민원 데이터
]
categories = ["환불요청", "배송문의", "기술지원"]  # 민원 카테고리

# 위와 유사한 방식으로 분류 모델 구축 가능
자연어처리BagOfWords텍스트벡터화텍스트마이닝감성분석