문서 단어 행렬(DTM) 의 단점, 중요한 단어에 대해서 가중치를 주지 못하는 단점을 보완한 방법이 단어 빈도-역 문서 빈도(TF-IDF: Term Frequency-Inverse Document Frequency) 이다. 문서의 빈도에 특정 식을 취하여 DTM 내의 각 단어들에 가중치를 주는 방법이다. TF-IDF 의 값이 높을수록 중요도가 높다. TF-IDF 의 특징은 모든 문서에서 자주 등장하는 a 나 the 같은 단어는 중요도가 낮다고 판단하며, 특정 문서에서만 자주 등장하는 단어를 중요도가 높다고 판단한다.



IF-IDF 에 적용되는 특정 식은 TF 값 과 IDF 값을 곱하는 것이다. (IDF 값은 DF 값의 역수이다.)

  • tf(d,t) : 특정 문서 d 에서의 특정 단어 t 의 등장 횟수.
  • df(t) : 특정 단어 t가 등장한 문서의 수.
  • idf(d,t) : df(t)에 반비례하는 수. n 을 총 문서 개수라고 할 때, 자연로그 ln(n/(1+df(t))) 


import pandas as pd
from math import log
 
docs = [
  '먹고 싶은 사과',
  '먹고 싶은 바나나',
  '길고 노란 바나나 바나나',
  '저는 과일이 좋아요'
]
 
vocab = list(set(w for doc in docs for w in doc.split()))  # 중복 제거, 단어 토큰화
vocab.sort()  # 오름차순 정렬 : ['과일이', '길고', '노란', '먹고', '바나나', '사과', '싶은', '저는', '좋아요']
 
= len(docs)  # 총 문서 수
 
def tf(t, d):
    return d.count(t)
 
def idf(t):
    df = 0
    for doc in docs:
        df += t in doc  # in 연산. True / False... True = 1
    return log(N/(df + 1))
 
def tfidf(t, d):
    return tf(t, d) * idf(t)
 
result = []
for i in range(N):  # 각 문서별
    result.append([])
    d = docs[i]
    for j in range(len(vocab)):
        t = vocab[j]
        result[-1].append(tf(t,d))  # tf : 문서별 단어 빈도수 구하기
        # [[0, 0, 0, 1, 0, 1, 1, 0, 0], [0, 0, 0, 1, ...
 
tf_ = pd.DataFrame(result, columns = vocab)
""" DTM
   과일이  길고  노란  먹고  바나나  사과  싶은  저는  좋아요
0    0   0   0   1    0   1   1   0    0
1    0   0   0   1    1   0   1   0    0
2    0   1   1   0    2   0   0   0    0
3    1   0   0   0    0   0   0   1    1
"""
 
result = []
for j in range(len(vocab)):
    t = vocab[j]
    result.append(idf(t))
 
idf_ = pd.DataFrame(result, index = vocab, columns = ["IDF"])
"""
          IDF
과일이  0.693147
길고   0.693147
노란   0.693147
먹고   0.287682
바나나  0.287682
사과   0.693147
싶은   0.287682
저는   0.693147
좋아요  0.693147
"""
 
result = []
for i in range(N):
    result.append([])
    d = docs[i]
    for j in range(len(vocab)):
        t = vocab[j]
        result[-1].append(tfidf(t,d))
 
tfidf_ = pd.DataFrame(result, columns = vocab)
"""
        과일이        길고        노란  ...        싶은        저는       좋아요
0  0.000000  0.000000  0.000000  ...  0.287682  0.000000  0.000000
1  0.000000  0.000000  0.000000  ...  0.287682  0.000000  0.000000
2  0.000000  0.693147  0.693147  ...  0.000000  0.000000  0.000000
3  0.693147  0.000000  0.000000  ...  0.000000  0.693147  0.693147
"""
cs


공교롭게도 바나나가 잘렸지만; 문서2 에서의 바나나 tfidf(0.28) 보다, 문서3 에서의 바나나 tfidf(0.57) 가 높은 것으로 보아 문서3 에서의 바나나가 더 중요하다는 것을 인식해야 한다.



TfidfVectorizer 를 이용한 TF-IDF


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)
print(tfidfv.transform(corpus).toarray())
print(tfidfv.vocabulary_)
 
"""
[[0.         0.46735098 0.         0.46735098 0.         0.46735098  0.         0.35543247 0.46735098]
 [0.         0.         0.79596054 0.         0.         0.          0.         0.60534851 0.        ]
 [0.57735027 0.         0.         0.         0.57735027 0.          0.57735027 0.         0.        ]]
{'you': 7, 'know': 1, 'want': 5, 'your': 8, 'love': 3, 'like': 2, 'what': 6, 'should': 4, 'do': 0}
"""
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,