rueki

문서 유사도 - 코사인 유사도(Cosine Similarity) 본문

DL/NLP

문서 유사도 - 코사인 유사도(Cosine Similarity)

륵기 2019. 7. 3. 09:36
728x90
반응형

코사인 유사도는 두 벡터 간의 코사인 각도를 이용하여 구할 수 있는 두 벡터의 유사도를 말한다.

두 벡터의 방향이 같으면 1, 직교일 때는 0, 서로 반대 방향이면 -1이다.

즉 1에 가까울 수록 유사도가 높다고 판단할 수 있다.

예제를 통해 코사인 유사도를 구해보자.

문서1 : 저는 사과 좋아요
문서2 : 저는 바나나 좋아요
문서3 : 저는 바나나 좋아요 저는 바나나 좋아요

 

위의 문서들에 대해 문서 단어 행렬을 만들면 밑의 표처럼 나온다

코사인 유사도를 numpy로 식을 만들어보자

from numpy import dot
from numpy.linalg import norm
import numpy as np
def cos_sim(A, B):
    return dot(A,B) / (norm(A)*norm(B))

doc1 = np.array([0,1,1,1])
doc2 = np.array([1,0,1,1])
doc3 = np.array([2,0,2,2])

print(cos_sim(doc1,doc2))
print(cos_sim(doc2,doc3))
print(cos_sim(doc1,doc3))
0.6666666666666667
1.0000000000000002
0.6666666666666667

각 문서간의 유사도 결과이다. 문서2와 문서3의 유사도는 1이 나왔으며 완전 동일한 경우라고 볼 수 있다.

 


유사도를 통해서 영화 데이터를 사용해서, 하나의 영화에 대해 유사한 영화목록을 뽑아내보자

import pandas as pd
data = pd.read_csv(r'가져올 영화데이터 위치')
data.head(2)

데이터의 상위 2개의 데이터만 뽑아왔다.

data = data.head(20000)
data['overview'] = data['overview'].fillna(' ')
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(stop_words='english')

영화 데이터의 overview, 즉 줄거리를 통해 유사도를 비교할 것이기 때문에 줄거리에 대해 전처리를 한다.

그리고 데이터가 많기에 20000개만 뽑기로 했다.

줄거리에서 키워드 중심 추출이 이루어 져야하기 때문에 불용어도 제거를 한다.

tfidf_matrix = tfidf.fit_transform(data['overview'])
print(tfidf_matrix.shape)
(20000, 47487)

20000개 데이터의 overview에서 47487개의 단어가 쓰인 것을 볼 수 있다.

이제 코사인 유사도를 구하면 문서의 유사도를 구할 수 있다.

from sklearn.metrics.pairwise import linear_kernel
cosine_sim = linear_kernel(tfidf_matrix, tfidf_matrix)
indices = pd.Series(data.index, index= data['title']).drop_duplicates()
print(indices.head())

제목이 같은 중복 데이터를 제거하고 영화 제목을 뽑아보자

title
Toy Story                      0
Jumanji                        1
Grumpier Old Men               2
Waiting to Exhale              3
Father of the Bride Part II    4
dtype: int64
idx= indices['Father of the Bride Part II']
print(idx)
4

영화의 타이틀과 인덱스를 가진 테이블을 생성했고, 특정 영화 타이틀에 대한 인덱스를 리턴받아보았다.

이를 통해서 이제 유사한 영화를 추출해보는 함수를 생성해보자

def get_recommendatioin(title, cosine_sim=cosine_sim):
    idx= indices[title]
    
    sim_scores = list(enumerate(cosine_sim[idx]))#모든 영화에 대해 해당 영화와의 유사도
    sim_scores = sorted(sim_scores,key=lambda x:x[1], reverse=True)#유사도 따라 영화들 정렬
    
    sim_scores = sim_scores[1:11] #유사한 영화 10개
    movie_indices = [i[0] for i in sim_scores]#10개으 영화 인덱스 받아온다
    
    return data['title'].iloc[movie_indices] #10개의 영화 제목 리턴
get_recommendatioin('The Dark Knight Rises')

다크나이트 라이즈와 유사한 영화는 무엇이 나올까?

12481                            The Dark Knight
150                               Batman Forever
1328                              Batman Returns
15511                 Batman: Under the Red Hood
585                                       Batman
9230          Batman Beyond: Return of the Joker
18035                           Batman: Year One
19792    Batman: The Dark Knight Returns, Part 1
3095                Batman: Mask of the Phantasm
10122                              Batman Begins
Name: title, dtype: object

거의 배트맨 영화가 다수인 것을 볼 수 있었다.

728x90
반응형
Comments