근본없는 코딩

TF-IDF란? 본문

✔ etc.

TF-IDF란?

근본없는 개발자 2024. 5. 1. 20:46

1. Vector Representation (벡터 표현)

** vector representation은 텍스트를 벡터로 표현하는 방법으로 텍스트를 벡터공간 상의 점으로 표시한다.

. m개의 review 문서가 있다고 가정하자.

. review 문서 전체에 등장하는 단어의 수는 n개이다.

. 각 항목은 해당 단어가 review에 등장하는 빈도수를 의미한다.

ex) (Review 1, Word 0) = 2 → Review 1에 Word 0은 2번 등장한다.

 

2. Term Vector Representation (단어 벡터 표현)

* Term Weight (단어 가중치)

. (i, j) = weight

. Term Frequency Vector: 단어의 빈도수로 벡터를 나타냄. 문서 i에서의 단어 j의 중요도

 

* TF - IDF (Term Freaquency * Inverse Document Frequency)

① 기본 내용

. 흔하게 등장하는 단어는 중요하지 않은 단어

   → ex) 조사는 많이 등장하지만 다른 명사들보다 의미가 떨어진다.

. Information Retrieval에서 많이 사용하는 개념

. 각 단어에 가중치를 부여해서 Keyword extraction 등에 활용

. 문서에서 특정 단어가 등장하는 것으로 문서끼리 관련있음을 표현할 수 있음

   → 영화 리뷰에 비슷한 단어들이 많이 나오면 그 영화는 사람들에게 비슷한 평가를 받는구나라고 생각 가능

 

② 개념

. TF: 단어(Word) w가 문서(Document) d에 등장한 빈도 수

. DF: 단어 w가 등장한 문서 d의 수

. N: 전체 문서의 수

 

. DF가 큰 단어는 정보력이 적다

→ 문서 Corpus(말뭉치)에 모두 포함된 단어는 흔히 등장하는 단어로, 의미가 크지 않다.

→ 흔하게 등장하는 단어는 유사도 계산에서도 제외하게 된다.

→ 대부분 문법적인 역할을 하는 조사, 관사 등이 해당된다.

 

 

➕ TF-IDF 이해하기

1) 사용 목적?

. 문서는 단어로 되어있다 → 각 단어별 문서의 연관성을 알고 싶을 때!

. TF-IDF는 수치로 된 값

 

2) TF (Term Frequency)

① TF: 문서가 주어졌을 때 이 단어가 몇번 출현했는지에 대한 값

→ 가설: 문서가 있을 때, 특정 단어가 여러번 출현했다면, 그 단어와 문서는 연관성이 높을 것이다.

 

. TF Score: 자주 출현할 수록 점수가 높아진다.

. 단점: 'a'와 같이 연관성은 없지만 여러 문장에 자주 출연하는 단어들이 있다.이로인해 문서와 연관성을 나타내기 어려워진다.

 

3) IDF (Inverse Document Frequency)

. 문서와 연관성이 없음에도 어느 문장에서나 자주 출현하는 단어들에 패널티를 주기 위한 개념

. 0이 되는걸 방지하기 위해 +1을 하는 smoothing을 사용하기도 한다.

 

. IDF Score를 산출하게 되면 아래와 같다.

 

4) TF-IDF score

. 정리) 문서가 주어졌을 때, 각 단어별로 그 문서에 연관성을 수치로 나타낸 값

 

 

3. 실습

1) 준비 과정

. kss: 한국어 문장 분리 모듈

→ 뉴스 데이터를 문장 단위로 쪼개기 위한 라이브러리, https://pypi.org/project/kss/

 

. konlpy 설치(윈도우 Windows에서 Mecab 설치)

https://velog.io/@bluebarry3/Google-Colab%EC%97%90%EC%84%9C-Mecab-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

. 특수문자나 숫자들을 전처리 하는 부분 (수업과는 무관하여 pass, 참고용!)

emoval_list =  "‘, ’, ◇, ‘, ”,  ’, ', ·, \“, ·, △, ●,  , ■, (, ), \", >>, `, /, -,∼,=,ㆍ<,>, .,?, !,【,】, …, ◆,%"

def cleansing_special(sentence):
    # 특수문자를 전처리를 하는 함수
    sentence = re.sub("[.,\'\"’‘”“!?]", "", sentence)
    sentence = re.sub("[^가-힣0-9a-zA-Z\\s]", " ", sentence)
    sentence = re.sub("\s+", " ", sentence)
    
    sentence = sentence.translate(str.maketrans(removal_list, ' '*len(removal_list)))
    sentence = sentence.strip()
    
    return sentence

def cleansing_numbers(sentence):
    # 숫자를 전처리(delexicalization) 하는 함수    
    sentence = re.sub('[0-9]+', 'NUM', sentence)
    sentence = re.sub('NUM\s+', "NUM", sentence)
    sentence = re.sub('[NUM]+', "NUM", sentence)
    
    return sentence

 

. cleansing == preprocess == 분석에 불필요한 부분들을 날려버리겠다.

  → 위쪽에 정의한 함수들을 통해 cleansing을 해준다

 

. 명사만 추출 → 목적 자체가 TF-IDF를 구하는 것 → 은/는/이/가 와 같은 조사들은 필요가 없다.

# 각자 작업 환경에 맞는 경로를 지정해주세요. Google Colab과 Jupyter환경에서 경로가 다를 수 있습니다.
data_path = '/content/drive/MyDrive/data'
all_sentences = []
with open(os.path.join(data_path, 'news_sample.txt'), 'r', encoding='utf-8') as f:
  for idx, line in enumerate(f.readlines()):
    print(f"--- 문서 {idx} 번 ---")
    preprocessed = cleansing_numbers(line)
    preprocessed = cleansing_special(preprocessed)
    # 명사만 추출하기
    preprocessed_news = ' '.join(list(set(mecab.nouns(preprocessed))))
    # 문장 분리해서 사용하는 방법
    # preprocessed_news = ' '.join(kss.split_sentences(preprocessed))
    print(preprocessed_news)
    all_sentences.append(preprocessed_news)

 

2) Scikit-learn을 사용한 TF-IDF

* TfidfVectorizer 모듈

from sklearn.feature_extraction.text import TfidfVectorizer
from collections import defaultdict

 

. 한글자 단어 제외
. https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html
. Useful option: tokenizer, stop_words

 

① all_sentences == 문서 1~20를 하나로 쭉 합쳐놓은 것

 

 

② all_sentences를 가지고 TF-IDF를 생성한다.

** 수업에서 제공된 예제와 차이점: get_feature_names_out()

tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(all_sentences)

word2id = defaultdict(lambda : 0)
for idx, feature in enumerate(tfidf_vectorizer.get_feature_names_out()):
    word2id[feature] = idx

 

 

③ 생성된 내용 조회하기

. vocabulary_: 입력된 단어와 고유 인덱스를 볼 수 있다.

 

.  생성된 TF-IDF의 matrix 모양 → (20, 2626) == 20개의 문서에서 2626개의 토큰으로 vectorize를 했다.

 

 

④ 문서별 TF-IDF 조회하기

for idx, sent in enumerate(all_sentences):
    print(f"--- 문서 {idx} 번 ---")
    results = [(token, tfidf_matrix[idx, word2id[token]]) for token in sent.split()]
    results.sort(key = lambda element : element[1], reverse=True)
    print(results)
    print("\n")