-목차-
1. Bag of Words란?
Bag of Words모델은 문서가 가지는 모든 단어(Words)를 문맥이나 순서를 무시하고 일괄적으로 단어에 대해 빈도 값을 부여해 피처 값을 추출하는 모델이다. 문서 내 모든 단어를 한꺼번에 봉투(Bag) 안에 넣은 뒤에 흔들어서 썩는다는 의미로 Bag of Word(BOW) 모델이라고 한다.
다음과 같은 2개의문장이 있다고 가정하고 이 문장을 Bag of Words의 단어 수(Word Count) 피처를 추출해보자.
문장 1 : My wife likes to watch baseball games and my daughter likes to watch baseball games too
문장 2: My wife likes to play baseball
- 문장 1과 문장 2에 있는 모든 단어에서 중복을 제거하고 각 단어를 컬럼 형태로 나열한다.
- 단어의 고유 인덱스를 부여한다.
- 'and' : 0, 'baseball' : 1, 'daughter' : 2, 'games' : 3, 'likes' : 4, 'my' : 5, 'play' : 6, 'to' : 7, 'too' : 8, 'watch' : 9, 'wife' : 10
- 개별 문장에서 해당 단어가 나타나는 횟수(Occurrence)를 각 단어(단어 인덱스)에 기재한다.
and | baseball | daughter | games | likes | my | play | to | too | watch | wife | |
문장 1 | 1 | 2 | 1 | 2 | 2 | 2 | 2 | 1 | 2 | 1 | |
문장 2 | 1 | 1 | 1 | 1 | 1 | 1 |
BOW 모델의 장점은 쉽고 빠른 구축에 있다. 단순히 단어의 발생 횟수에 기반하고 있지만, 예상보다 문서의 특징을 잘 나타낼 수 있는 모델이어서 전통적으로 여러 분야에서 활용도가 높다.
2. BOW 피처 벡터화
머신러닝 알고리즘은 일반적으로 숫자형 피처를 데이터로 입력받아 동작하기 때문에 텍스트와 같은 데이터는 머신러닝 알고리즘에 바로 입력할 수가 없다. 따라서 텍스트는 특정 의미를 가지는 숫자형 값이 벡터 값으로 변환해야 한다. 이러한 변환을 피처 벡터화라고 한다.
BOW 모델에서 피처 벡터화를 수행한다는 것은 모든 문서에서 모든 단어를 칼럼 형태로 나열하고 각 문서에 해당 단어의 횟수나 정규화된 빈도를 값으로 부여하는 데이터셋 모델로 변경하는 것이다. 예를 들어 M개의 텍스트 문서가 있고, 이 문서에서 모든 단어를 추출해 나열했을 때 N개의 단어가 있다고 가정하면 문서의 피처 벡터화를 수행하면 M x N개의 단어 피처로 이뤄진 행렬을 구성하게 된다.
일반적으로 BOW의 피처 벡터화는 두 가지 방식이 있다.
- 카운트 기반의 벡터화
- TF-IDF(Term Frequency - Inverse Document Frequency) 기반의 벡터화
단어 피처에 값을 부여할 때 각 문서에서 해당 단어가 나타나는 횟수, 즉 Count를 부여하는 경우를 카운트 벡터화라고 한다. 카운트 벡터화는 카운트 값이 높을수록 중요한 단어로 인식된다. 그러나 언어의 특성상 문장에서 자주 사용될 수밖에 없는 단어까지 높은 값을 부여하게 되는데 이러한 문제를 보완한 것이 TF-IDF(Term Frequency - Inverse Document Frequency) 벡터화이다.
TF-IDF는 개별 문서에서 자주 나타나는 단어에 높은 가중치를 주되, 모든 문서에서 전반적으로 자주 나타나는 단어에 대해서는 페널티를 주는 방식으로 값을 부여한다.
\(TF_i\) = 개별 문서에서의 단어 \(i\)의 빈도
\(DF_i\) = 단어 \(i\)를 가지고 있는 문서 개수
\(N\) = 전체 문서 개수 일때 TF-IDF벡터 값은 다음과 같이 구해진다.
\[TFIDF_i = TF_i \times \log \frac{N}{DF_i}\]
3. BOW 벡터화를 위한 희소 행렬
모든 문서에 있는 단어를 추출해 이를 피처로 벡터화하는 방법은 필연적으로 많은 피처 칼럼을 만들 수밖에 없다. 그런데 이러한 대규모의 행렬이 생성되더라도 레코드의 각 문서가 가지는 단어의 수는 제한적이기 때문에 이 행렬의 값을 대부분 0이 차지하게 되는 희소 행렬이 된다.
이러한 희소 행렬은 너무 많은 불필요한 0 값이 메모리 공간에 할당되어 메모리 공간이 많이 필요하며, 행렬의 크기가 커서 연산 시에도 데이터 액세스를 위한 시간이 많이 소모된다. 이러한 희소 행렬을 물리적으로 적은 메모리 공간을 차지할 수 있도록 변환하는 대표적인 방법으로는 COO(Coordinate : 좌표) 형식과 CSR(Compressed Sparse Row) 형식이 있다.
3.1 COO(Coordinate) 형식
COO형식은 0이 아닌 데이터만 별도의 데이터 배열에 저장하고, 그 데이터가 가리키는 행과 열의 위치를 별도의 배열로 저장하는 방식이다. 예를 들어 [[3, 0, 1], [0, 2, 0]]과 같은 2차원 데이터가 있다고 가정하자. 0이 아닌 데이터는 [3, 1, 2]이며 0이 아닌 데이터가 있는 위치를 (row, col)로 표시하면 (0, 0), (0, 2), (1, 1)이 된다. 이 로우와 칼럼을 별도의 배열로 저장하면 로우는 [0, 0, 1] 칼럼은 [0, 2, 1]이 된다.
위에서 설명한 데이터 배열, 로우 배열, 칼럼 배열만 저장한다면 행렬을 전부 메모리에 가지고 있지 않아도 원본 행렬을 다시 복원할 수 있다.
3.2 CSR(Compressed Sparse Row)형식
CSR 형식은 COO 형식이 행과 열의 위치를 나타내기 위해서 반복적인 위치 데이터를 사용해야 하는 문제점을 해결한 방식이다. 먼저 COO 변환 형식의 문제점을 알아보자. 다음과 같은 2차원 배열을 COO형식으로 변환해보자
[[0,0,1,0,0,5],
[1,4,0,3,2,5],
[0,6,0,3,0,0],
[2,0,0,0,0,0],
[0,0,0,7,0,8],
[1,0,0,0,0,0]]
0이 아닌 데이터 : [1, 5, 1, 4, 3, 2, 5, 6, 3, 2, 7, 8, 1]
row_pos : [0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5]
col_pos : [2, 5, 0, 1, 3, 4, 5, 1, 3, 0, 3, 5, 0]
이때 행 위치 배열인 row_pos : [0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5]를 보면 순차적인 같은 값이 반복적으로 나타남을 알 수 있다. CSR은 행 위치 배열 내에 있는 고유한 값의 시작 위치만 다시 별도의 위치 배열로 변환하는 방식을 사용한다.
row_pos : [0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5]를 CSR로 변환하면 [0, 2, 7, 9, 10, 12]가 된다. 그리고 가장 마지막에 데이터의 총 항목 개수를 배열에 추가한다. 최종적으로 CSR 변환되는 배열은 [0, 2, 7, 9, 10, 12, 13]이 된다. 이렇게 고유 값의 시작 위치만 알고 있으면 얼마든지 행 위치 배열을 다시 만들 수 있기 때문에 COO 방식보다 메모리가 적게 들고 빠른 연산이 가능하다.
참고 자료
'머신러닝, 딥러닝 > NLP' 카테고리의 다른 글
[논문 리뷰, GPT-2]Language Models are Unsupervised Multitask Learners (0) | 2022.05.05 |
---|---|
[논문 리뷰, GPT]Improving Language Understanding by Generative Pre-Training (0) | 2022.05.03 |
[ML] 텍스트 전처리(텍스트 정규화) (0) | 2022.03.03 |
댓글