Bag of Words는 텍스트의 단어 순서를 완전히 무시하고,
**단어의 등장 빈도(frequency)**에만 집중하는 단어 표현 방법입니다.
단어 집합(Vocabulary) 생성
단어 빈도 벡터화
문서1: 정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다.
BoW 결과:
vocabulary: {'정부':0, '가':1, '발표':2, '하는':3, '물가상승률':4, ...}
vector: [1, 2, 1, 1, 2, ...]
물가상승률
(index=4)은 문서 내에서 2번 등장 → 해당 위치 값이 2
여러 문서를 하나의 단어 집합으로 통일한 뒤, 각 문서별 BoW를 생성할 수 있습니다.
같은 단어라도 문서마다 등장 빈도가 다르기 때문에, BoW 값이 다름
예:
'달리기', '체력', '근력'
단어가 많이 등장 → 체육 관련 문서'미분', '방정식', '부등식'
단어가 많이 등장 → 수학 관련 문서scikit-learn
의 CountVectorizer로 BoW를 손쉽게 생성할 수 있습니다.
from sklearn.feature_extraction.text import CountVectorizer
corpus = ['you know I want your love. because I love you.']
vector = CountVectorizer()
print(vector.fit_transform(corpus).toarray())
print(vector.vocabulary_)
출력:
[[1 1 2 1 2 1]]
{'you':4, 'know':1, 'want':3, 'your':5, 'love':2, 'because':0}
you
, love
는 2번씩 등장물가상승률과
/ 물가상승률은
→ 다른 단어로 인식Okt
, Mecab
)를 이용하는 것이 좋음BoW는 단어 중요도와 무관하게 모든 단어를 카운트하기 때문에,
의미 없는 단어(불용어)를 제거하면 성능이 향상될 수 있습니다.
from sklearn.feature_extraction.text import CountVectorizer
text = ["Family is not an important thing. It's everything."]
vect = CountVectorizer(stop_words="english")
print(vect.fit_transform(text).toarray())
print(vect.vocabulary_)
출력:
[[1 1 1]]
{'family':0, 'important':1, 'thing':2}
"is", "not"
등 제거됨장점: 단순하고 구현이 쉬움
단점:
📌 정리
# 한국어 형태소 분석기를 이용한 BoW 구현
from konlpy.tag import Okt
okt = Okt()
def build_bag_of_words(document):
# 마침표 제거
document = document.replace('.', '')
# 형태소 분석
tokenized_document = okt.morphs(document)
# 단어 집합과 BoW 초기화
word_to_index = {}
bow = []
for word in tokenized_document:
if word not in word_to_index.keys():
# 새로운 단어면 인덱스 부여
word_to_index[word] = len(word_to_index)
bow.insert(len(word_to_index) - 1, 1) # 등장 횟수 1로 시작
else:
# 기존 단어면 등장 횟수 +1
index = word_to_index.get(word)
bow[index] = bow[index] + 1
return word_to_index, bow
# 테스트 문서
doc1 = "정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다."
vocab, bow = build_bag_of_words(doc1)
# 해당 인덱스는 어떻게 되는가?
print("📌 Vocabulary:", vocab)
# 해당 인덱스의 단어가 몇번 등장 하는가?
print("📌 BoW Vector:", bow)
###################################
doc2 = "소비자는 주로 소비하는 상품을 기준으로 물가상승률을 느낀다."
# 문서 합치기
doc3 = doc1 + " " + doc2
vocab3, bow3 = build_bag_of_words(doc3)
print("\n📌 문서3 Vocabulary:", vocab3)
print("📌 문서3 BoW Vector:", bow3)
# 문서3 단어 집합 기준으로 문서1 BoW 만들기
def build_bow_with_vocab(document, fixed_vocab):
document = document.replace('.', '')
tokenized_document = okt.morphs(document)
bow = [0] * len(fixed_vocab)
for word in tokenized_document:
if word in fixed_vocab:
index = fixed_vocab[word]
bow[index] += 1
return bow
bow_doc1_fixed = build_bow_with_vocab(doc1, vocab3)
bow_doc2_fixed = build_bow_with_vocab(doc2, vocab3)
print("\n📌 문서3 단어 집합 기준 문서1 BoW:", bow_doc1_fixed)
print("📌 문서3 단어 집합 기준 문서2 BoW:", bow_doc2_fixed)
##############################
from sklearn.feature_extraction.text import CountVectorizer
corpus = ['you know I want your love. because I love you.']
vectorizer = CountVectorizer()
# BoW 벡터
X = vectorizer.fit_transform(corpus).toarray()
# 단어 인덱스
vocab = vectorizer.vocabulary_
print("\n📌 BoW Vector (영어):", X)
print("📌 Vocabulary (영어):", vocab)
###############################
# 방법 1: 직접 불용어 지정
vect_custom_stop = CountVectorizer(stop_words=["the", "a", "an", "is", "not"])
X_custom = vect_custom_stop.fit_transform(["Family is not an important thing. It's everything."]).toarray()
print("\n📌 Custom Stopwords BoW:", X_custom)
print("📌 Vocabulary:", vect_custom_stop.vocabulary_)
# 방법 2: 영어 내장 불용어
vect_en_stop = CountVectorizer(stop_words="english")
X_en = vect_en_stop.fit_transform(["Family is not an important thing. It's everything."]).toarray()
print("\n📌 English Stopwords BoW:", X_en)
print("📌 Vocabulary:", vect_en_stop.vocabulary_)