David의 개발 이야기!

Bag of Words(BoW)에 대해 알아보자 본문

자연어처리

Bag of Words(BoW)에 대해 알아보자

david.kim2028 2023. 8. 9. 17:21
반응형

1. Bag of Words 란

단어들의 순서는 전혀 고려하지 않고, 단어들의 출현빈도(frequency)에만 집중하는 텍스트데이터의 수치화 표현 방법이다. BoW를 직역하면, 단어들의 가방이라는 뜻으로, 어떤 텍스트의 단어들을 전부가방에 넣고, 섞었을때, 해당 가방에서, 특정 단어가 N번 등장했다면, 해당 문서에는 그 특정 단어가 N개 있다고 생각하는 것이다. (단어의 순서는 섞어서 진행했기에 중요하지 않다.)

 

BoW를 만드는 과정은 아래와 같다. 

(1) 각 단어에 고유한 정수 인덱스를 부여합니다. # 단어 집합 생성.

(2) 각 인덱스의 위치에 단어 토큰의 등장 횟수를 기록한 벡터를 만들기

 

2. 기본 구현 코드

from konlpy.tag import Okt

okt = Okt()

def build_bag_of_words(document):
  # 온점 제거 및 형태소 분석
  document = document.replace('.', '')
  tokenized_document = okt.morphs(document)
  
  print(tokenized_document)
  
  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에 전부 기본값 1을 넣는다.
      bow.insert(len(word_to_index) - 1, 1)
    else:
      # 재등장하는 단어의 인덱스
      index = word_to_index.get(word)
      # 재등장한 단어는 해당하는 인덱스의 위치에 1을 더한다.
      bow[index] = bow[index] + 1

  return word_to_index, bow
doc1 = "AI Engineer 가 되는 그날까지 함께 파이팅!"
vocab, bow = build_bag_of_words(doc1)
print('vocabulary :', vocab)
print('bag of words vector :', bow)
#출력 결과

['AI', 'Engineer', '가', '되는', '그날', '까지', '함께', '파이팅', '!'] //tokenized_document 결과
vocabulary : {'AI': 0, 'Engineer': 1, '가': 2, '되는': 3, '그날': 4, '까지': 5, '함께': 6, '파이팅': 7, '!': 8}
bag of words vector : [1, 1, 1, 1, 1, 1, 1, 1, 1] // bow 결과

 

결국, BoW는 각 단어가 빈도를 표현하는 방법이므로, 어떤 단어가 얼마나 등장했는지를 기준으로 문서의 성격을 판단하는 작업에 쓰인다. 코딩, 파이썬 이런 단어가 많을 경우, 개발 문서로, 닭가슴살, 팔굽혀펴기, 웨이트 이런 단어가 많이 나오면, 헬스 주제로 분류할 수 있다.

 

3. 사이킷런을 통해 BoW 구현하기 

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}

-> 주의 : I는 빠져있는데, CountVectorizer는 기본적으로 길이가 2인 이상인 문자에 대해서만 토큰으로 인식함

-> 한국어의 경우, 띄어쓰기로만, 단어를 구분할 수 없으므로 적용하기 어려움이 있다. 

 

ex) 밥을 먹었다. 밥이 먹고 싶다 에서, '밥'은 같지만, CountVectorizer는 다르게 인식하게 된다.

 

4. 불용어를 제거한 BOW 만들기 -> CounterVectorizer 임으로 영어의 경우

불용어 == 의미를 갖지 않는 단어

 

from sklearn.feature_extraction.text import CountVectorizer
from nltk.corpus import stopwords

 

(1) 사용자가 직접 정의한 불용어 사용

text = ["Family is not an important thing. It's everything."]
vect = CountVectorizer(stop_words=["the", "a", "an", "is", "not"])
print('bag of words vector :',vect.fit_transform(text).toarray())
print('vocabulary :',vect.vocabulary_)
bag of words vector : [[1 1 1 1 1]]
vocabulary : {'family': 1, 'important': 2, 'thing': 4, 'it': 3, 'everything': 0}

 

(2) CounterVectorizer에서 제공하는 자체 불용어 사용

text = ["Family is not an important thing. It's everything."]
vect = CountVectorizer(stop_words="english")
print('bag of words vector :',vect.fit_transform(text).toarray())
print('vocabulary :',vect.vocabulary_)
bag of words vector : [[1 1 1]]
vocabulary : {'family': 0, 'important': 1, 'thing': 2}

 

(3) NLTK에서 지원하는 불용어 사용

text = ["Family is not an important thing. It's everything."]
stop_words = stopwords.words("english")
vect = CountVectorizer(stop_words=stop_words)
print('bag of words vector :',vect.fit_transform(text).toarray()) 
print('vocabulary :',vect.vocabulary_)
bag of words vector : [[1 1 1 1]]
vocabulary : {'family': 1, 'important': 2, 'thing': 3, 'everything': 0}
반응형
Comments