Bag of Words
정의
- 가장 간단하게 텍스트를 표현(수치화) 하는 방법
- 문서가 포함하는 단어들의 빈도로 벡터를 만드는 방법이다.
- 가장 기초적이고 원시적인 방식의 텍스트 표현 방법이다.
만드는 방법
- 모든 문서에 등장한 모든 단어에 고유한 인덱스를 부여해 단어 주머니(Bag of Words)를 만든다.
- 각 문서에 등장하는 단어들의 등장 횟수(count)를 해당 단어의 인덱스에 대응하는 값으로 넣는다.
장점과 단점
- 장점 : 간단하고 구현이 쉽고, 문서의 주제 파악에 유용하다.
- 단점 : 단어의 순서를 완전히 무시하며, 단어가 많아질 경우 벡터 차원이 커지고 Sparse Vector가 되기 쉽다.
Bag of Words 만들어보기
실습 데이터
- gensim 의 샘플 데이터를 활용한다.
- text corpus 는 9개의 문장으로 이루어져 있다.
1
2
3
4
5
6
7
8
9
10
11
text_corpus = [
"Human machine interface for lab abc computer applications",
"A survey of user opinion of computer system response time",
"The EPS user interface management system",
"System and human system engineering testing of EPS",
"Relation of user perceived response time to error measurement",
"The generation of random binary unordered trees",
"The intersection graph of paths in trees",
"Graph minors IV Widths of trees and well quasi ordering",
"Graph minors A survey",
]
설치
- gensim 라이브러리를 설치한다.
- gensim은 자연어 처리를 위한 오픈소스 파이썬 라이브러리로 주로 토픽 모델링과 단어 임베딩을 효율적으로 처리하기 위해 설계되었다.
1
pip install gensim
전처리
- for, a, of, the, and 등의 stop-words를 문장에서 제거한다.
- 문장에서 등장하는 단어를 소문자로 바꾼다.
- 단어의 등장 빈도를 count 한다.
- 모든 문장에서 두 번 이상 등장한 단어만을 유지한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Create a set of frequent words
stoplist = set('for a of the and to in'.split(' '))
# Lowercase each document, split it by white space and filter out stopwords
texts = [[word for word in document.lower().split() if word not in stoplist]
for document in text_corpus]
# Count word frequencies
from collections import defaultdict
frequency = defaultdict(int)
for text in texts:
for token in text:
frequency[token] += 1
# Only keep words that appear more than once
processed_corpus = [[token for token in text if frequency[token] > 1] for text in texts]
pprint.pprint(processed_corpus)
1
2
3
4
5
6
7
8
9
10
# 결과
[['human', 'interface', 'computer'],
['survey', 'user', 'computer', 'system', 'response', 'time'],
['eps', 'user', 'interface', 'system'],
['system', 'human', 'system', 'eps'],
['user', 'response', 'time'],
['trees'],
['graph', 'trees'],
['graph', 'minors', 'trees'],
['graph', 'minors', 'survey']]
사전 만들기
- 전처리를 통해 걸러진 단어들에 대해 고유의 인덱스를 부여한다.
- 인덱스 - 단어 쌍으로 이루어진 사전을 제작한다.
- 사전이 만들어졌다면, BoW를 위한 기본적인 준비는 끝난 것이다.
1
2
3
4
5
from gensim import corpora
dictionary = corpora.Dictionary(processed_corpus)
print(dictionary)
pprint.pprint(dictionary.token2id)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 출력
Dictionary<12 unique tokens: ['computer', 'human', 'interface', 'response', 'survey']...>
{'computer': 0,
'eps': 8,
'graph': 10,
'human': 1,
'interface': 2,
'minors': 11,
'response': 3,
'survey': 4,
'system': 5,
'time': 6,
'trees': 9,
'user': 7}
샘플 문장들을 BoW로 표현하기
- 만들어진 단어 사전을 이용해 처음에 주어진 샘플 문장들을 BoW를 통해 벡터로 만들어보자.
- 4번 문장에서 system이 2회 등장함을 볼 수 있다.
- 빈도가 0인 단어들은 표시되지 않는다.
1
2
3
4
5
pprint.pprint(processed_corpus) # 샘플 문장들을 전처리 한 결과 리스트
bow_corpus = [dictionary.doc2bow(text) for text in processed_corpus] # BoW
# dictionary.doc2bow() : BoW 를 통한 벡터 만들기
print("="*50)
pprint.pprint(bow_corpus)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 출력
[['human', 'interface', 'computer'],
['survey', 'user', 'computer', 'system', 'response', 'time'],
['eps', 'user', 'interface', 'system'],
['system', 'human', 'system', 'eps'],
['user', 'response', 'time'],
['trees'],
['graph', 'trees'],
['graph', 'minors', 'trees'],
['graph', 'minors', 'survey']]
==================================================
[[(0, 1), (1, 1), (2, 1)],
[(0, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)],
[(2, 1), (5, 1), (7, 1), (8, 1)],
[(1, 1), (5, 2), (8, 1)], # system 2회
[(3, 1), (6, 1), (7, 1)],
[(9, 1)],
[(9, 1), (10, 1)],
[(9, 1), (10, 1), (11, 1)],
[(4, 1), (10, 1), (11, 1)]]
새로운 단어를 BoW 로 벡터화 하기
- “Human computer interaction” 이라는 새로운 문장이 들어왔다.
- 이를 BoW 로 벡터화를 해본다면 아래와 같다.
1
2
3
new_doc = "Human computer interaction"
new_vec = dictionary.doc2bow(new_doc.lower().split())
print(new_vec)
1
2
3
4
5
# 출력
[(0, 1), (1, 1)]
# 0번 단어 (computer) : 1회 등장
# 1번 단어 (human) : 1회 등장
# interaction : 단어사전에 포함되지 않은 단어
Reference
방송통신대학교 - 자연언어처리 수업 (유찬우 교수)
gensim 샘플 데이터 및 코드
https://wikidocs.net/24557
Comments