2024.03.02 - [Lectures/Basic NLP] - Introduction & Word Vectors
이전글에서 언급했듯이, 앞으로 Word Embedding에 대해 차근차근 소개할 예정이다.
가장 먼저, 소개할 부분은 Deep-learning의 근간이 되는 Machine-learning 알고리즘으로는 볼 수 없는 방식이다.
물론, Machine-learning 알고리즘이 아닐 뿐 이를 통해 텍스트를 벡터화하여 Machine-learning 모델을 학습할 수는 있다.
기초적인 방식이기에, 가장 직관적인 Count를 기반으로 Word Represenation을 표현해 embedding한다.
Bag of Words (BoW)
단어들의 순서들을 전혀 고려하지 않고 오로지 Count기반인 출현 빈도수(Frequency)에 따라 표현하는 방식이다.
이름 그대로 단어들에 따라서 단어 가방을 만들고, 해당 단어가 출현할 때마다 가방에 없는 경우 넣어주고 있는 경우는 frequency를 증가시켜서 구성한다.
doc1 = "정부가 발표하는 물가상승률과 소비자가 느끼는 물가상승률은 다르다."
vocab, bow = build_bag_of_words(doc1)
print('vocabulary :', vocab)
print('bag of words vector :', bow)
#결과
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]
Basic code
BoW의 경우, 직접 function을 만들어서 사용해도 상관없으나 sklearn에서 library를 제공하기에 해당 library를 사용하면 아주 빠르게 코드를 구현할 수 있다.
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}
Considering Stopwords
Stopwords란, 불용어를 의미한다. count 기반으로만 모든 단어들을 고려하게 된다면, 한국어의 경우 "은, 는, 이, 가" 영어의 경우 "a, the"처럼 실제 의미는 크게 가지지 않는 단어들이 의미를 가진 단어들에 비해 높은 frequency를 가지기 때문이다.
따라서, 이를 고려하는 것이 성능적 측면에서 도움이 된다.
이를 고려하는 방법 역시, 직접 코드를 통해 고려할 수도 있고 아니면 library를 활용해서 고려할 수도 있다.
from sklearn.feature_extraction.text import CountVectorizer
#사용자가 직접 Stopwords 고려하기
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}
#CountVectorizer Libaray를 활용한 Stopwords 고려하기
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}
#NLTK Libaray를 활용한 Stopwords 고려하기
from sklearn.feature_extraction.text import CountVectorizer
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}
Document-Term Matrix (DTM)
DTM이란 각 문서에 나온 모든 단어들에 대한 빈도에 대한 행렬을 의미한다.
다음 예시를 보면 아주 쉽게 이해할 수 있다.
- 문서 1: 먹고 싶은 사과
- 문서 2: 먹고 싶은 바나나
- 문서 3: 길고 노란 바나나 바나나
- 문서 4: 저는 과일이 좋아요
정말 frequency에 대한 행렬이기 때문에 아주 간단하다는 장점을 가지나 여전한 단점이 존재한다.
- 공간이 낭비된다: 모든 단어들에 대해 행렬을 만들게 되면 대부분의 경우 0으로 이뤄진 sparse 한 행렬로 인해 많은 저장 공간이 필요하고 이에 대한 계산 역시 시간이 많이 소모된다.
- Stopwords에 대한 처리 불가: BoW와 동일하게 Stopwords, 불용어에 대한 처리가 효율적이지 못하다. 강제로 직접 일일이 제거하지 않는 경우 말고는 크게 처리 방법이 없는 점이 단점이다.
역시, 코드를 직접 작성하여도 무방하나 sklearn에서 library를 제공하기에 간단히 작성이 가능하다.
from sklearn.feature_extraction.text import CountVectorizer
corpus = [
'you know I want your love',
'I like you',
'what should I do ',
]
vector = CountVectorizer()
# 코퍼스로부터 각 단어의 빈도수를 기록
print(vector.fit_transform(corpus).toarray())
# 각 단어와 맵핑된 인덱스 출력
print(vector.vocabulary_)
Term Frequency - Inverse Document Frequency (TF-IDF)
Stopwords에 대한 문제는 단어에 대한 가중치가 없다는 것에서 비롯된다.
이를 극복하기 위해 등장한 방식이, TF-IDF로 수식을 통해 각 단어에 대한 가중치를 계산하여 고려하는 방식이다.
가중치를 주기 위해서 단어의 빈도수(Term Frequency)와 단어의 역 빈도수(Inverse Document Frequency)를 활용한다.
TF-IDF를 구하기 위해서는 위에서 구했던 DTM을 먼저 생성한 후에 DTM에 있는 단어들에 대해 가중치를 부여하는 과정으로 진행한다.
가중치의 경우 이름이 TF와 IDF인 것처럼 둘의 곱으로 이뤄진다.
수식을 이해하기 위해 필요한 term은 다음과 같다.
- d: 문서
- t: 단어
- n: 문서의 총 개수
TF: tf(d, t)로 구성된다. 즉, 특정 문서 d에서 특정 단어 t의 빈도 수로 앞서 구한 DTM 내 값들과 동일하다.
DF: df(t)로 특정 단어 t가 등장한 특정 문서 d의 개수를 의미한다.
IDF: idf(t)로 df(t)에 반비레 하는 수이다. 단순한 역수가 아닌 이유는 값이 기하급수적으로 커지는 것을 방지하기 위해 log를 취한 값을 사용한다. (1을 더해주는 것은 분모가 0이 되는 것을 방지하는 역할이다.)
해당 수식을 활용하면, Stopwrods의 경우 모든 문서에서 등장하는 경우가 많을 것이기에 df(t) 값이 커지게 된다.
따라서, idf(t) 값은 반대로 작아지기에 Stopwords들에 대해 가중치를 덜 줄 수 있게 되는 원리인 것이다.
이 역시, sklearn에서 library를 제공한다.
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
'you know I want your love',
'I like you',
'what should I do ',
]
tfidfv = TfidfVectorizer().fit(corpus)
이번 글에서는 Count based Word Representation에 대해 알아보았다.
다음 글에서는 Deep-learning의 기반이 되는 Mahcine-learning 알고리즘에 속하는 Word Embedding 방식인 Statistics based Word Representation에 대해 알아보겠다. (틀린 말은 아닌데, 말이 굉장히 복잡해 보이지만 이 역시 다음 글 들에서 용어들을 정리해 나가도록 하겠다)
'Lectures > Basic NLP' 카테고리의 다른 글
Language Model (0) | 2024.04.17 |
---|---|
Introduction & Word Vectors (0) | 2024.03.02 |