Bag of Words란
Bag of Words란 단어들의 순서는 전혀 고려하지 않고, 단어들의 출현 빈도에만 집중하는 텍스트 데이터의 수치화 표현 방법이다. Bag of Words를 직역하면 단어들의 가방이라는 의미이다. 단어들이 들어있는 가방을 상상해보자. 갖고 있는 어떤 텍스트 문서에 있는 단어들을 가방에다가 전부 넣는다. 그 후에 이 가방을 흔들어 단어들을 섞는다. 만약, 해당 문서 내에서 특정 단어가 N번 등장했다면, 이 가방에는 그 특정 단어가 N개 있게 된다. 또한 가방을 흔들어가 단어를 섞었기 떄문에 더 이상 단어의 순서는 중요하지 않다.
BoW를 만드는 과정을 이렇게 두 가지 과정으로 생각해보자.
1. 각 단어에 고요한 정수 인덱스를 부여한다. # 단어 집합 생성
2. 각 인덱스의 위치에 단어 토큰의 등장 횟수를 기록한 벡터를 만든다.
한국어 예제를 통해서 BoW에 대해서 이해해보자.
문서 1 : 정부가 발표하는 물가 상승률과 소비자가 느끼는 물가상승률은 다르다.
문서 1에 대해 BoW를 만들어보자. 아래의 함수는 입력된 문서에 대해 단어 집합을 만들어 각 단어에 정수 인덱스를 할당하고, BoW를 만든다.
해당 함수에 문서1을 입력으로 넣어보자.
출력 결과 :
vocabulary : {'정부': 0, '가': 1, '발표': 2, '하는': 3, '물가상승률': 4, '과': 5, '소비자': 6, '느끼는': 7, '은': 8, '다르다': 9}
Bag of Words vector : [1, 2, 1, 1, 2, 1, 1, 1, 1, 1]
문서1에 각 단어에 대해서 인덱스를 부여한 결과는 첫 번째 출력 결과이다. 문서1의 BoW는 두 번째 출력 결과이다. 두번째 출력 결과를 보면, 인덱스 4에 해당하는 물가상승률은 2번 언급되었기 때문에 인덱스 4에 해당하는 값이 2이다.
Bag of Words의 다른 예제들
문서2 : 소비자는 주로 소비하는 상품을 기준으로 물가상승률을 느낀다.
출력 결과 :
vocabulary : {'소비자': 0, '는': 1, '주로': 2, '소비': 3, '하는': 4, '상품': 5, '을': 6, '기준': 7, '으로': 8, '물가상승률': 9, '느낀다': 10}
Bag of Words vector : [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1]
문서3 : 정부가 발표하는 물가 상승률과 소비자가 느끼는 물가상승률은 다르다. 소비자는 주로 소비하는 상품을 기준으로 물가상승률을 느낀다.
출력 결과 :
vocabulary : {'정부': 0, '가': 1, '발표': 2, '하는': 3, '물가': 4, '상': 5, '승률': 6, '과': 7, '소비자': 8, '느끼는': 9, '물가상승률': 10, '은': 11, '다르다': 12, '는': 13, '주로': 14, '소비': 15, '상품': 16, '을': 17, '기준': 18, '으로': 19, '느낀다': 20}
Bag of Words vector : [1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1]
BoW는 각 단어가 등장한 횟수를 수치화하는 텍스트 표현 방법이므로 주로 어떤 단어가 얼마나 등장했는지를 기준으로 문서가 어떤 성격의 문서인지를 판단하는 작업에 쓰인다. 즉, 분류 문제나 여러 문서 간의 유사도를 구하는 문제에 주로 쓰인다. 가령, '달리기', '체력', '근력'과 같은 단어가 자주 등장하면 해당 문서를 체육 관련 문서로 분류할 수 있을 것이며, '미분', '방정식', '부등식'과 같은 단어가 자주 등장한다면 수학 관련 문서로 분류할 수 있다.
CounterVectorizer 클래스로 BoW 만들기
사이킷 런에서는 단어의 빈도를 Count하여 vector로 만드는 CountVectorizer 클래스를 지원한다. 이를 이용하면 영어에 대해서는 쉽게 BoW를 만들 수 있다.
출력 결과 :
Bag of Words vector : [[1 1 2 1 2 1]]
vocabulary : {'you': 4, 'know': 1, 'want': 3, 'your': 5, 'love': 2, 'because': 0}
예제 문장에서는 you와 love가 두 번씩 언급되었으므로 각각 인데스 2와 4에 대해서 2의 값을 가지며, 그 외의 값에서는 1의 값을 가지는 것을 볼 수 있다. 또한, 알파벳 I는 BoW를 만드는 과정에서 사라졌는데, 이는 CountVectorizer가 기본적으로 길이가 2 이상인 문자에 대해서만 토큰으로 인식하기 때문이다. 정제(Cleaning) 챕터에서 언급했듯이, 영어에서는 길이가 짧은 문자를 제거하는 것 또한 전처리 작업으로 고려되기도 한다.
주의할 것은 CountVectorizer는 단지 띄어쓰기만을 기준으로 단어를 자르는 낮은 수준의 토큰화를 진행하고 BoW를 만든다는 점이다. 이는 영어의 경우 띄어쓰기만으로 토큰화가 수행되기 때문에 문제가 없지만 한국어에 CountVectorizer를 적용하면, 조사 등의 이유로 제대로 BoW가 만들어지지 않음을 의미한다.
예를 들어, 앞서 BoW를 만드는데 사용했던 '정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다.'라는 문장을 CountVectorizer를 사용하여 BoW로 만들 경우, CountVectorizer는 '물가상승률'이라는 단어를 인식하지 못한다. CountVectorizer는 띄어쓰기를 기준으로 분리한 뒤에 '물가상승률'와 '물가상승률은'으로 조사를 포함해서 하나의 단어로 판단하기 때문에 서로 다른 두 단어로 인식한다. 그리고 '물가상승률과'와 '물가상승률은'이 각자 다른 인덱스에서 1이라는 빈도의 값을 갖게 된다.
불용어를 제거한 BoW 만들기
앞서 불용어는 자연어 처리에서 별로 의미를 갖지 않는 단어들이라고 언급한 바 있다. BoW를 사용한다는 것은 그 문서에서 각 단어가 얼마나 자주 등장했는지를 보겠다는 것이다. 그리고 각 단어에 대한 빈도수를 수치화하겠다는 것은 결국 텍스트 내에서 어떤 단어들이 중요한지를 보고 싶다는 의미를 함축하고 있다. 그렇다면 BoW를 만들 때 불용어를 제거하는 일은 자연어 처리의 정확도를 높이기 위해서 선택할 수 있는 전처리 기법이다.
영어의 BoW를 만들기 위해 사용하는 CountVectorizer는 불용어를 지정하면, 불용어는 제외하고 BoW를 만들 수 있도록 불용어 제거 기능을 지원하고 있다.
CounterVextorizer에서 지원하는 자체 불용어 사용
출력 결과 :
Bag of Words vector : [[1 1 1]]
vocabulary : {'family': 0, 'important': 1, 'thing': 2}
NLTK에서 지원하는 불용어 사용
출력 결과 :
Bag of Words vector : [[1 1 1 1]]
vocabulary : {'family': 1, 'important': 2, 'thing': 3, 'everything': 0}
'NLP > 딥러닝을 이용한 자연어 처리 입문' 카테고리의 다른 글
[NLP] 3-4. TF-IDF(Term Frequency-Inverse Document Frequency) (1) | 2023.12.26 |
---|---|
[NLP] 3-3. 문서 단어 행렬(DTM) (0) | 2023.12.26 |
[NLP] 3-1. 다양한 단어의 표현 방법 (0) | 2023.12.21 |
[NLP] 3. 카운트 기반의 단어 표현 (0) | 2023.12.21 |
[NLP] 2-4. 펄플렉시티(Perplexity, PPL) (1) | 2023.12.20 |