Colab으로 하루에 하나씩 딥러닝

텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_2)코사인 유사도 본문

딥러닝_개념

텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_2)코사인 유사도

Elleik 2022. 12. 21. 23:05
728x90

코사인 유사도(cosine similarity)

  • 카운트 벡터의 활용으로 문서 간 유사도를 측정하여 사용함,  이때에 유사도 계산에 가장 많이 사용되는 척도
  • 두 벡터가 이루는 각도의 코사인 값으로 정의
  • 두 개의 벡터가 있을 때 벡터의 크기는 중요하지 않고 벡터의 방향성만 비교(= 각 문서는 단 두개의 단어 빈도로만 이루어져 있을 때 사용)
  • 각도에 따른 유사도로 비교 하기 위해선 코사인 커브를 사용
  • 특징 
    • 단어별 빈도는 최솟값이 0이므로, 좌표 표현상 각 벡터는 1 사분면에만 위치함
    • 따라서 두 벡터 간의 각도 차이가 90˚가 넘어가지 않음
    • 즉 두 벡터간의 가장 먼 경우에도 유사도는 90˚에 대한 코사인 값인 0보다 작아지는 경우는 없음
    • 결론적으로 두 벡터가 가장 가까우면(각도가 일치하면) 유사도는 1, 가장 먼 경우(각도가 가장 크면) 유사도가 0
### 코사인 커브 만들기

%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib as mpl

# 그래프에서 마이너스 폰트 깨지는 문제에 대한 대처
mpl.rcParams['axes.unicode_minus'] = False

import numpy as np
x = np.arange(0, 2*np.pi, 0.1) # start,stop,step
y = np.cos(x)
plt.plot(x,y)
plt.show()

코사인 커브 결과


코사인 유사도(cosine similarity) 실습

2022.12.19 - [딥러닝_개념] - 텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_1)카운트 기반/BOW의 문서 표현

 

텍스트 마이닝_ 1. BOW 기반의 텍스트 마이닝_1)카운트 기반/BOW의 문서 표현

카운트 기반 문서 표현 문서의 의미를 반영해 벡터를 만드는 과정 단어의 빈도를 파악하여 문서의 내용을 파악 ex) 막대그래프, 워드 클라우드 전체 말뭉치에 한 번이라도 사용된 단어는 문서에

elleik.tistory.com

이전 게시물의 영화 리뷰를 기반으로 실습 진행하기 때문에 이전글 확인 후 아래의 실습을 보시는걸 추천드립니다.
### 이전 게시물의 데이터및 라이브러리 호출

# data 준비, movie_reviews.raw()를 사용해 raw text를 추출
import nltk
nltk.download('movie_reviews')
nltk.download('stopwords')

from nltk.corpus import movie_reviews
from sklearn.feature_extraction.text import CountVectorizer
from nltk.tokenize import RegexpTokenizer
from nltk.corpus import stopwords # 일반적으로 분석대상이 아닌 단어들


reviews = [movie_reviews.raw(fileid) for fileid in movie_reviews.fileids()]


# words() 대신 raw()로 원문을 가져옴
documents = [movie_reviews.raw(fileid) for fileid in movie_reviews.fileids()]

tokens = [[token for token in tokenizer.tokenize(doc) if token not in english_stops] for doc in documents]
word_count = {}
for text in tokens:
  for word in text:
    word_count[word] = word_count.get(word, 0) + 1


sorted_features = sorted(word_count, key=word_count.get, reverse=True)
# 빈도가 높은 상위 1,000개의 단어만 추출해 features를 구성
word_features = sorted_features[:1000]
# 
cv = CountVectorizer(vocabulary=word_features)

# reviews를 이용해 count vector를 학습하고, 변환
reviews_cv = cv.fit_transform(reviews)

tokenizer = RegexpTokenizer("[\w']{3,}")  # 정규표현식으로 토크나이저를 정의
english_stops = set(stopwords.words('english')) # 영어 불용어를 가져옴

<순서>

  • 첫째 리뷰의 뒷부분 절반을 잘라서 유사도를 측정할 대상 문서를 만듦
  • 유사도 측정이 제대로 되다면 새로 만든 문서와 가장 유사한 문서로 첫째 리뷰가 될 것
  • 코사인 유사도를 계산하기 위해서 카운트 벡터가 필요하므로 해당 문서를 카운트 벡터 변환하고 유사도를 측정
### NLTK 영화 리뷰 문서의 유사도 측정

from sklearn.metrics.pairwise import cosine_similarity

# 첫째 리뷰의 문자수를 확인하고 뒤 절반을 가져오기 위해 중심점을 찾음
start = len(reviews[0]) // 2

# 중심점으로부터 뒤 절반을 가져와서 비교할 문서를 생성
source = reviews[0][-start:]

# 코사인 유사도는 카운트 벡터에 대해 계산하므로 벡터로 변환
# transform은 반드시 리스트나 행렬 형태의 입력을 요구하므로 리스트로 만들어서 입력
source_cv = cv.transform([source])

# 행렬의 크기를 확인, 문서가 하나이므로 (1,1000)
print("대상 특성 행렬의 크기:", source_cv.shape)

# 변환된 count vector와 기존 값들과의 similarity 계산
sim_result = cosine_similarity(source_cv, reviews_cv)

print("유사도 계산 행렬의 크기: ", sim_result.shape)
print("유사도 계산결과를 역순으로 정렬: ", sorted(sim_result[0], reverse=True)[:5])

타 리뷰와 비교될정도로 약 0.84의 유사도값을 갖는 리뷰가 있음

### 유사도가 가장 높은 리뷰의 인덱스 확인하기

import numpy as np

print('가장 유사한 리뷰의 인덱스: ', np.argmax(sim_result[0]))

첫번째 리뷰가 가장 높은 유사도를 가진 것을 알 수 있음

참고: 박상언, 『파이썬 텍스트 마이닝 완벽 가이드』, 위키북스(2022)