본문으로 바로가기

Text Similarity Analysis (텍스트 유사도 분석) _ 이론

1) TF-IDF

: Term Frequency - Inverse Document Frequency

- 어떤 특정 단어가 문서나 말뭉치에서 어떤 중요도 가지는지 나타내는 지표

- 단어 갯수 그대로 count하는 CountVectorizer와 달리, TfidfVectorizer는 많은 문서에 공통적으로 들어있는 단어의 경우 문서 구별 능력이 떨어진다고 보아 가중치를 축소한다.

- 즉, Common Word에 더 작은 가중치를 곱해주고, Rare Word에 더 높은 가중치를 곱해준다.

- 계산 과정은 아래 그림을 보면 잘 나와있다.

 

https://towardsdatascience.com/tf-term-frequency-idf-inverse-document-frequency-from-scratch-in-python-6c2b61b78558

 

 

2) Cosine Similarity

: 거리 계산 방법 중 하나

- 두 벡터 사이 각도의 코사인값을 이용하여 측정하는 값

- 두 벡터의 유사한 정도를 의미

   ( -1 ) : 서로 완전히 반대되는 경우

   ( 0 ) : 서로 독립인 경우

   ( 1 ) : 서로 완전히 다른 경우

https://towardsdatascience.com/calculating-document-similarities-using-bert-and-other-models-b2c1a29c9630

 


Text Similarity Analysis (텍스트 유사도 분석) _ 실습

실습1) 두 개의 영화 리뷰 텍스트 간 유사도 계산하기

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

# 영화1 : shawshank
file = open('shawshank.txt', 'r', encoding = 'utf-8')
lines = file.readlines()
doc1 = ' '.join(lines)   # python 문자열 합치기

# 영화2 : godfather
file = open('godfather.txt', 'r', encoding = 'utf-8')
lines = file.readlines()  # 영화 리뷰 파일의 모든 라인을 읽어와 리스트로 저장
doc2 = ' '.join(lines)

# doc1, doc2를 합쳐 corpus list를 생성
corpus = [doc1, doc2]
'''TfidfVectorizer() 객체 변수 생성'''
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus).todense()
# 0.0000000이라는 숫자만 나오면 메모리의 낭비 -> 0인 것들은 아예 생각하지 않도록
# .todense(): 기본적으로 fit_transform의 결과로 만들어지는 행렬은 희소행렬(Sparse matrix)
# 풀어서 말하자면, 0들도 채워서 나오도록 해서 우리 눈으로 보고 싶을 때 사용
# .todense() 함수 실행하지 않더라도 코사인 유사도 계산값은 동일하며, 메모리 면에서도 사실 안쓰는 것이 나음

# vectorizer에 저장된 각 단어를 확인하고 싶을 때
vectorizer.get_feature_names()

# 희소행렬(Sparse matrix)를 확인하고 싶을 때
# (확인하기 위해서는 반드시 .todense()를 적용해야 함)
import pandas as pd
pd.DataFrame(X)

'''코사인 유사도 출력'''
print("Similarity between 'The Shawshank Redemption' and 'The Godfather': ", cosine_similarity(X[0], X[1]))

 

 

실습2) 여러 개의 영화 리뷰 텍스트 간 유사도 계산하기

### 1. 텍스트 데이터 str 자료형으로 준비
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)

### (2. 형태소 분석, 불용어 제거까지 진행해주면 좋음)

### 3. TF-IDF 계산'''
corpus = [doc1, doc2, doc3]
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus)  #.todense() 


### 4. 영화 간 cosine similarity 계산
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]))

 

 

추가로 아래는 일일이 하나씩 짝지어 계산을 명령하기 어려울 때 쓰는 방법이다.

# + [ 하나의 행 vs 전체 행 ] 구도로 Cosine similarity 계산
pd.DataFrame( cosine_similarity(X[0], X).T )


# + [ 각 행 vs 전체 행 ] 구도로 Cosine similarity 계산
result = pd.DataFrame(cosine_similarity( X , X ))
result.columns = ['Shawshank', 'Godfather', 'Inception']
result.index = ['Shawshank', 'Godfather', 'Inception']
result

 

더하여, 시각화까지 진행하면 아래와 같이 그릴 수 있다.

import seaborn as sns
import matplotlib.pyplot as plt

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

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

sns.set(font_scale=1.5)
plt.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False)
plt.show()