기록하는삶

[파이썬/Python] 자연어처리 _ Bow, CountVectorizer 본문

AI/파이썬(Python)

[파이썬/Python] 자연어처리 _ Bow, CountVectorizer

mingchin 2021. 8. 7. 18:32
728x90
반응형

Bow(Bag of Words)

단어의 순서는 고려하지 않고, 출현 빈도만으로 텍스트를 수치화하는 방법

1) 각 단어에 고유한 정수 인덱스 부여(단어 사전)

2) 각 인덱스 위치에 해당 단어의 출현 빈도를 기록한 벡터 표현

 

아래와 같이 형태소 분석기 Okt를 이용, 직접 만들어 볼 수도 있다.

from konlpy.tag import Okt
import re 
# 형태소 분석기 Okt
okt=Okt() 
token=re.sub("(\.)","","정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다.") 
token=okt.morphs(token)  
word2index={} 
bow=[] 

for voca in token: 
    if voca not in word2index.keys(): 
        word2index[voca]=len(word2index) 
        bow.insert(len(word2index)-1,1) 
    else:
        index=word2index.get(voca)
        bow[index]=bow[index]+1
print("단어사전:",word2index)
print("Bow:", bow)

즉, 특정 단어가 문장 내에서 몇 번씩 사용되었는가를 기준으로 벡터화한다.

 

CountVectorizer

sklearn에서 제공하는 CountVectorizer를 이용, 쉽게 이를 구현할 수 있다.

from sklearn.feature_extraction.text import CountVectorizer
text=["똥 정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다."]
vector = CountVectorizer()
print(vect.fit_transform(text).toarray()) 
print(vect.vocabulary_)
print("="*100)
text=["Family is not an important thing. It's everything."]
vect = CountVectorizer(stop_words=["the", "a", "an", "is", "not"])
print(vect.fit_transform(text).toarray()) 
print(vect.vocabulary_)
print("="*100)
vect = CountVectorizer(stop_words="english")
print(vect.fit_transform(text).toarray())
print(vect.vocabulary_)

# nltk 패키지가 제공하는 stopwords도 있다.
from nltk.corpus import stopwords
sw = stopwords.words("english")

띄어쓰기를 기준으로 하기 때문에 '물가상승률과'와 '물가상승률은'을 다르게 count한 것을 확인할 수 있다. 이와 같이 한글을 다룰 때는 조사, 접사 등 영어보다 신경쓸 부분이 많다.

stop_words를 직접 설정할 수도 있고, 제공하는 것을 사용할 수도 있다. CountVectorizer는 's를 삭제하고(it's -> it), it, everything 등을 불용어로 처리함을 알 수 있다. 또한 I, a 등 한 글자의 단어는 불용어가 아니어도 자동으로 삭제한다. (위의 한글 예시에서 똥도 같은 이유로 삭제)

 

[Parameters]

① ngram_range : tuple (min, max), default = (1, 1)

띄어쓰기를 기본으로 토큰화를 진행하지만, 때로는 단어와 단어의 조합이 의미를 갖는 경우가 있다. (e.g. go back)

따라서 최소 min개, 최대 max개의 단어 구성으로 토큰을 구성하게 할 수 있다. (내부적인 판단 기준은 모르겠다.)

아래는 예시(family important???)

② max_df, min_df : 0~1 float 또는 int, default: max_df =1.0, min_df = 1

(int) 최소 min_df개, 최대 max_df개의 문장에 걸쳐 포함된 단어만을 단어 꾸러미에 포함.

(float) 최소 min_df, 최대 max_df 비율만큼의 문장에 걸쳐 포함된 단어만을 단어 꾸러미에 포함.

 

stop_words : english’ 또는 list, default = None 

자체 제공하는 영어 불용어 사용하거나, 리스트로 직접 입력해줄 수 있다.

 

④ analyzer :word’ or ‘char’ or ‘char_wb’, default = word 

토큰을 단어 단위로 나눌지(analyzer = word), 글자 단위로 나눌지(analyzer = char)

글자 단위로 나누는게 무슨 의미가 있나 싶지만,, 효과를 본 적이 있다는 글도 보았다.

char_wb는 단어의 앞 뒤에 space(' ')를 추가한 뒤 글자 단위로 토큰화한다. (이게 뭔 기능,,?)

 

token_pattern : string or 정규표현식, default = '(?u)\\b\\w\\w+\\b'(white space 사이의 문자+숫자) 

analyzer = word 일 때 사용 가능한 것으로 보인다. 특정 string 자체 혹은 정규표현식에 해당하는 단어만을 토큰화 할 수 있다. 아래는 예시. '~가' 형태의 단어들만 토큰화 되었다.

⑥ tokenizer : 토큰 생성 함수, default = None .

사용할 일이 있는지 모르겠지만, 다른 tokenizer를 사용해 토큰화를 진행하고 싶은 경우.

ex) CountVectorizer(tokenizer=nltk.word_tokenize).fit(text) (nltk가 제공하는 word_tokenize 사용)

 

[활용]

BoW는 각 단어가 등장한 횟수를 수치화하는 텍스트 표현 방법이기 때문에, 주로 어떤 단어가 얼마나 등장했는 지를 기준으로 분류 문제나 문서 간의 유사도를 구하는 문제에 쓰인다. 

ex) '달리기', '체력', '근력'과 같은 단어가 자주 등장 -> 체육 관련 문서

'미분', '방정식', '부등식'과 같은 단어가 자주 등장 -> 수학 관련 문서

 

[Cons]

의미 없이 자주 사용되는 단어(조사, 대명사 등)를 제대로 제거하지 못한다면, 유의미하지 않은 벡터가 만들어질 수 있다.

-> tf-idf로 해결 

728x90
반응형