Silver bullet
TF-IDF & Cosine similarity 이론 본문
1. TF-IDF (Term Frequency - Inverse Document Frequency)
- 어떤 특정 단어 (문장의 구성요소)가 문서나 말뭉치에서 어떤 중요도를 가지는지를 나타내는 지표
- 단어를 갯수 그대로 카운트하지 않고, 많은 문서에 공통적으로 들어있는 단어의 경우 문저 구별 능력이 떨어진다고 보아 가중치를 축소하는 방법
- Scikit-learn의 TfidfVectorizer : 문서들에서 단어의 수를 세고 TF-IDF 방식으로 단어의 가중치를 조정한 벡터를 만든다.
- Scikit-learn의 CountVectorizer : 문서에서 단어 출현 빈도 count
* log는 숫자의 대소관계는 유지하되, 스케일을 낮추는 효과가 있다.
2. Cosine similarity (코사인 유사도)
- 두 벡터 사이 각도의 코사인값을 이용하여 측정하는 값으로, 두 벡터의 유사한 정도를 의미
- 계산된 유사도는 -1에서 1까지의 값을 가지며, -1은 서로 완전히 반대되는 경우, 0은 서로 독립적인 경우, 1은 서로 완전히 같은 경우를 의미
- 텍스트 매칭에 적용될 경우, A, B의 벡터로는 일반적으로 해당 문서에서의 단어 빈도가 사용된다.
1. 두 개의 영화 리뷰 텍스트 간 유사도 계산하기
# 유사도 분석에 필요한 패키지를 불러온다
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity
file = open('shawshank.txt', 'r', encoding = 'utf-8')
lines = file.readlines() # 영화 리뷰 파일의 모든 라인을 읽어와 리스트로 저장
doc1 = ' '.join(lines)
# doc1 = '' # 리뷰 데이터를 담기 위한 String 변수 생성
# for line in lines: # for문을 통해 lines에 있는 모든 텍스트를 doc1에 이어 붙임
# doc1 += line
file = open('godfather.txt', 'r', encoding = 'utf-8')
lines = file.readlines() # 영화 리뷰 파일의 모든 라인을 읽어와 리스트로 저장
doc2 = ' '.join(lines)
CountVectorizer
corpus = [doc1, doc2] # doc1, doc2를 합쳐 corpus list를 생성
# corpus[0]
vectorizer = CountVectorizer() # CountVectorizer() 객체 변수 생성
vectorizer.fit(corpus)
result = vectorizer.transform(corpus).todense()
pd.DataFrame(result)
TfidfVectorizer
import pandas as pd
vectorizer = TfidfVectorizer() # TfidfVectorizer() 객체 변수 생성
vectorizer.fit(corpus)
result = vectorizer.transform(corpus).todense()
pd.DataFrame(result)
len(vectorizer.get_feature_names())
vectorizer.get_feature_names() # 단어 확인
fit과 transform 한번에 하기
X = vectorizer.fit_transform(corpus).todense()
# X = vectorizer.fit_transform(corpus) # .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)
# 정리하자면 원래 fit_transform(corpus)는 0이 없는 지도 형태로 주어지고, .todense()는 0을 채워 Dense matrix를 만들어 제공함.
코사인 유사도 확인
print("Similarity between 'A' and 'B': ", cosine_similarity(X[0], X[1])) # 코사인 유사도
* 최종 코드
with open('A.txt', 'r', encoding = 'utf-8') as f:
lines = f.readlines() # 영화 리뷰 파일의 모든 라인을 읽어와 리스트로 저장
doc1 = ' '.join(lines)
with open('B.txt', 'r', encoding= 'utf-8') as f:
lines = f.readlines() # 영화 리뷰 파일의 모든 라인을 읽어와 리스트로 저장
doc2 = ' '.join(lines)
corpus = [doc1, doc2] # doc1, doc2를 합쳐 corpus list를 생성
vectorizer = TfidfVectorizer() # TfidfVectorizer() 객체 변수 생성
X = vectorizer.fit_transform(corpus) # fit_transform()를 통해 corpus의 텍스트 데이터를 벡터화해 X에 저장하고 X를 dense한 matrix로 변환
print("Similarity between 'A' and 'B': ", cosine_similarity(X[0], X[1]))
2. [하나의 행 vs 전체 행] 구도로 Cosine similarity 계산 (비교할 문서가 많을 때)
corpus = [doc1, doc2, doc3]
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus).todense()
cosine_similarity( X[0] , X ) # 기준이 되는 행을 넣고, 통째로 넣으면 각각 자동으로 비교가 됨
df = pd.DataFrame( cosine_similarity(X[0], X).T ) # T == Transpose (전치 행렬)
df.columns=['simil_score']
df['movie_names'] = ['Shawshank', 'Godfather', 'Inception']
df
df.sort_values(by='simil_score', ascending=False)
3. [각 행 vs 전체 행] 구도로 Cosine similarity 계산 (비교할 문서가 많을 때)
cosine_similarity( X , X )
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 환경세팅
sns.set(font_scale=1.5)
plt.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False) # Let the horizontal axes labeling appear on top.
plt.show()'AI > AI' 카테고리의 다른 글
| 기초 Numpy & Pandas (0) | 2024.07.02 |
|---|---|
| 한글 텍스트 데이터 전처리 (0) | 2024.07.02 |
| 품사별 토큰 추출 & 등장횟수 시각화, 정규 표현식 (0) | 2024.07.01 |
| Tokenizing, POS tagging, Stopwords, Lemmatization (0) | 2024.07.01 |
| 정형 데이터 전처리 & 시각화 (0) | 2024.07.01 |