TF-IDF
역문서 빈도, 각 단어의 중요성을 가중치로 표현
tf(d,t) -한 문서 안에서 어떤 단어가 몇번 등장했는지
df(t) -단어가 얼마나 많은 문서에 등장했는지
idf(d,t) -df(t)의 역수
idf가 높으면, df가 낮은 경우 의미
tf와 달리 idf쪽에는 주로 로그를 사용한다.
idf에 로그를 사용하는 이유는 단어A 와 B/ 단어 C와 D는 한개 차이지만,
빈도수가 적을때, 그 차이가 적더라도 가중치를 높게 측정한다.
단어 C와 D를 봤을 때 빈도수가 둘 다 많으면, 차이가 미미하다.
그래서 이러한 효과를 상쇄하기 위해 로그를 적용한다.
TF-IDF의 계산 절차
토큰별 인덱스는 위치를 부여한다.
TF 계산은 각 토큰의 등장 빈도를 계산하고, IDF 계산은 각 단어의 문서 등장빈도를 계산하여 역수를 취한다.
마지막으로 TF와 IDF를 곱하여 계산한다.
문서1 The cat sat on my face I hate a cat
문서 2 The dog sat on my bed I love a dog 가 있다고 가정하자.
tf를 알기 위해서는문서내 전체 토큰 빈도(전체 단어 수) 와 각 단어의 문서내 토큰빈도(문서내 단어가 나온 수)를 알아야한다.
문서내 토큰 빈도/ 문서내 전체 로 나누어 tf를 구한다.
idf계산하기 위해서 전체 문서수 알아야한다.
The는 공통적으로 등장하는데, log1=0 결론은 idf=0이 나옴.
해당문서안의 단어가 빈도수가 많고, 타 문서 안에서 낮게 나오면 tf-idf가 높게
해당문서에 많이 나오지 않고, 타문서에 많이 등장하면 tf-idf가 낮다.
tf-idf 스코어 가지고 벡터로 나타낼 수 있다.
예를 들어 한 단어의 문서1 tf-idf가 0.06이고, 문서2의 tf-idf가 0이면 (0.06,0) 으로 나타낸다.
code
d1 = "The cat sat on my face I hate a cat"
d2 = "The dog sat on my bed I love a dog"
import numpy as np
def tf(t, d): # t가 d문서에서 등장한 횟수/d의 전체토큰수
return d.count(t)/len(d)
def idf(t, D): #전체 문서에서 t단어가 얼마나 많이 등장했는지
N = len(D)
n = len([True for d in D if t in d]) #전체 문서안에 개별 문서 탐색 그중에서 t가 d에 포함된것,
return np.log(N/n)
def tokenizer(d): #토큰화는 공백으로 처리
return d.split()
def tfidf(t,d,D): #D는 전체문서수
return tf(t,d)*idf(t, D)
def tfidf_scorer(D):
docs = [tokenizer(d) for d in D]
result = []
for d in docs:
for t in d:
result.append([(t,tfidf(t,d,docs)) for t in d])
#단어별 tfidf 스코어 계산/ 문서별 단어별 tfidf 계산
return result
tfidf_scorer([d1,d2])
[[('The', 0.0),
('cat', 0.13862943611198905),
('sat', 0.0),
('on', 0.0),
('my', 0.0),
('face', 0.06931471805599453),
('I', 0.0),
('hate', 0.06931471805599453),
('a', 0.0),
('cat', 0.13862943611198905)],
[('The', 0.0),
('dog', 0.13862943611198905),
('sat', 0.0),
('on', 0.0),
('my', 0.0),
('bed', 0.06931471805599453),
('I', 0.0),
('love', 0.06931471805599453),
('a', 0.0),
('dog', 0.13862943611198905)]]
sklearn 활용
from sklearn.feature_extraction.text import CountVectorizer
docs = [d1,d2]
count_vect = CountVectorizer()
countv = count_vect.fit_transform(docs)
#fit학습, trasform은 예측 fit_transform은 둘다함.
countv.toarray() #단어별로 카운팅
array([[0, 2, 0, 1, 1, 0, 1, 1, 1, 1],
[1, 0, 2, 0, 0, 1, 1, 1, 1, 1]], dtype=int64)
count_vect.vocabulary_ #간 단어가 어떻게 INDEX표시 되었는지
{'the': 9,
'cat': 1,
'sat': 8,
'on': 7,
'my': 6,
'face': 3,
'hate': 4,
'dog': 2,
'bed': 0,
'love': 5}
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vect = TfidfVectorizer()
tfidfv = tfidf_vect.fit_transform(docs)
print(tfidfv.toarray())
print(tfidf_vect.vocabulary_)
[[0. 0.70600557 0. 0.35300279 0.35300279 0.
0.25116439 0.25116439 0.25116439 0.25116439]
[0.35300279 0. 0.70600557 0. 0. 0.35300279
0.25116439 0.25116439 0.25116439 0.25116439]]
{'the': 9, 'cat': 1, 'sat': 8, 'on': 7, 'my': 6, 'face': 3, 'hate': 4, 'dog': 2, 'bed': 0, 'love': 5
N-gram
n개의 단어를 보느냐에 따라 unigram, bigram, trigram으로 구분
제한적으로 문맥을 표현 가능
unigrams : a, cute, little, boy
bigrams : a cute, a boy
trigrams: a cute boy
n을 1보다 2로 설정하는 것이 모델 성능을 높일 수 있음, n을 크게 하면 n-gram이 unique할 확률이 높아 등장수가 낮을 확률이 높음.
n을 너무 작게하면 카운트는 잘되지만 정확도가 떨어질 수 있음.
n카운트가 0이 되는경우, 딕셔너리가 있을때 그 딕셔너리에 새로운 ngram이 포함될 확률이 낮을 수 있음
출처: https://github.com/insightcampus/sesac-nlp
'Deep Learning > NLP' 카테고리의 다른 글
07. TF-IDF(단어빈도-역문서빈도) (0) | 2023.03.18 |
---|---|
06. Bag of Words, TDM (0) | 2023.03.17 |
04. One- Hot Encoding, Similarlity (0) | 2023.03.13 |
03. 영문 텍스트 전처리 (0) | 2023.03.12 |
02. BeautifulSoup 이용한 네이버 뉴스 데이터 수집 (0) | 2023.03.10 |