개발 블로그

[Python] TF-IDF, Cosine Similarity 본문

Programming Language/Python

[Python] TF-IDF, Cosine Similarity

draidev 2022. 3. 28. 20:35

01 TF-IDF (Term Frequency - Inverse Document Frequency)

TF-IDF(Term Frequency - Inverse Document Frequency)는 정보 검색과 텍스트 마이닝에서 이용하는 가중치로, 여러 문서로 이루어진 문서군이 있을 때 어떤 단어가 특정 문서 내에서 얼마나 중요한 것인지를 나타내는 통계적 수치입니다. 문서의 핵심어를 추출하거나, 검색 엔진에서 검색 결과의 순위를 결정하거나, 문서들 사이의 비슷한 정도를 구하는 등의 용도로 사용할 수 있습니다.
(출처 : wiki tf-idf)

https://class101.dev/ko/blog/2019/07/16/esmond/

 

02 Cosine Similarity (코사인 유사도)

코사인 유사도(cosine similarity)는 내적공간의 두 벡터간 각도의 코사인값을 이용하여 측정된 벡터간의 유사한 정도를 의미합니다. 각도가 0°일 때의 코사인값은 1이며, 다른 모든 각도의 코사인값은 1보다 작습니다. 따라서 이 값은 벡터의 크기가 아닌 방향의 유사도를 판단하는 목적으로 사용되며, 두 벡터의 방향이 완전히 같을 경우 1, 90°의 각을 이룰 경우 0, 180°로 완전히 반대 방향인 경우 -1의 값을 갖습니다. 

코사인 유사도는 어떤 개수의 차원에도 적용이 가능하여 흔히 다차원의 양수 공간에서의 유사도 측정에 자주 이용됩니다. 예를 들어 정보 검색  텍스트 마이닝 분야에서, 단어 하나 하나는 각각의 차원을 구성하고 문서는 각 단어가 문서에 나타나는 회수로 표현되는 벡터값을 가집니다. 이러한 다차원 공간에서 코사인 유사도는 두 문서의 유사도를 측정하는 매우 유용한 방법입니다.

(출처 : wiki 코사인 유사도)

 

https://deepai.org/machine-learning-glossary-and-terms/cosine-similarity

 

 

두개의 벡터인 A와 B에 대해서 유사도를 구하는 공식은 다음과 같습니다.

코사인 유사도 공식

참고 블로그 : https://jiho-ml.com/weekly-nlp-5/

 

 

03. 여러 영화 리뷰 텍스트 간 유사도 계산하기

위의 이론을 바탕으로 한 Python의 sklearn라이브러리를 통해서 영화 리뷰의 유사도 계산을 진행했습니다.

아래의 sklearn의 TfidfVectorizer, cosine_similarity 모듈을 import 해줍니다.

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

영화 리뷰 텍스트 파일들을 가져왔습니다.

file = open('shawshank.txt', 'r', encoding = 'utf-8')
lines = file.readlines()  
doc1 = ' '.join(lines)

file = open('godfather.txt', 'r', encoding = 'utf-8')
lines = file.readlines()  
doc2 = ' '.join(lines)

file = open('inception.txt', 'r', encoding = 'utf-8')
lines = file.readlines()
doc3 = ' '.join(lines)

그리고 3가지 데이터를 한 번에 비교하기 위하여 corpus변수에 리스트 형태로 대입해주고, TfidfVectorizer() 객체변수도 생성해줬습니다.

fit_transform( )를 보면 다음과 같습니다. (출처 : scikit learn)

단어와 idf를 학습하고, 문서 단어 행렬(document-term matrix)를 반환한다고 되어있습니다.

이러한 행렬을 todense( )함수로 압축시키고 cosine_similarity( )함수에 각각의 영화리뷰 행렬의 인덱스를 부여한 X값을 전달인자로 하여 코사인 유사도를 구합니다.

corpus = [doc1, doc2, doc3] # n개의 데이터를 넣을 수 있다
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus).todense()

# .todense() 함수를 실행하지 않더라도 코사인 유사도 계산에는 차이가 없음

# .todense()의 역할 : 기본적으로 fit_transform의 결과로 만들어지는 행렬은 희소행렬(Sparse matrix), 
# 희소행렬 내에는 무수히 많은 '0'이 존재하는데 이러한 '0'이라는 값을 저장하는 것 역시도 공간(메모리)을 차지하므로, 
# '0'인 값들은 아예 제외하고 나머지 숫자들만 실제로 저장하는 방식으로 처리함 (ex. 0이 아닌 값만 [행/열/값] 쌍으로 저장하는 방식 등)
# 이렇게 저장된 데이터로부터 현재 우리가 얻어내야하는 것은 값이 모두 채워진 행렬(Dense matrix)이므로,
# 마지막에 .todense() 함수를 실행 시 Sparse matrix로부터 2행 3276열 크기의 Dense matrix를 만들어 돌려받을 수 있음 
# (추가 참고 : Scipy sparse matrix handling @ https://j.mp/32mhwGq)


print("Similarity between 'The Shawshank Redemption' and 'The Godfather': ", cosine_similarity(X[0], X[1]))
print("Similarity between 'The Shawshank Redemption' and 'Inception': ", cosine_similarity(X[0], X[2]))
print("Similarity between 'The Godfather' and 'Inception': ", cosine_similarity(X[1], X[2]))

값을 보면 '쇼생크 탈출'과 '대부'는 유사도가 높지만 앞의 둘과 '인셉션'은 리뷰의 유사도가 낮은것을 확인 할 수 있습니다.

코사인 유사도 출력

 

03_01 [ 각 행 vs 전체 행 ] 구도로 Cosine similarity 계산, seaborn 시각화

참고 : https://wikidocs.net/76347

cosine_similarity( )함수에서 아래 둘의 결과 값은 3x3행렬로 같습니다.

cosine_similarity( X , X )
cosine_similarity( X )

cosine_similarity( X ) 출력

위의 값을 DataFrame으로 만들고 시각화를 진행하면 다음과 같습니다.

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

result = pd.DataFrame(cosine_similarity( X ))

result.columns = ['Shawshank', 'Godfather', 'Inception']
result.index = ['Shawshank', 'Godfather', 'Inception']

plt.figure(figsize=(10, 10))

sns.heatmap(result, annot=True, fmt='f', linewidths=5, cmap='RdYlBu')

sns.set(font_scale=2)
plt.tick_params(top=True, bottom=False, labeltop=False, labelbottom=False) # Let the horizontal axes labeling appear on top.
plt.show()

Comments