본문 바로가기
데이터 분석/데이터 분석

개인화 추천 알고리즘 3 : 컨텐츠 기반 모델과 유사도 함수

by thomasito 2022. 2. 7.
반응형

콘텐츠 기반 추천 알고리즘

 개인화 추천 알고리즘에 가장 기초적인 형태는 앞서 언급한 연관분석(Apriori, FP-growth)이다. 연관분석은 이재호님의 글에서 좋은 이미지가 있어서 가져 왔는데, 주로 상품추천이나 상품배치에 많이 사용된다. 

 

출처 : http://www.sbr.ai/news/articleView.html?idxno=1582 

 

 상품 추천 이외에도 컨텐츠를 추천해주는 방법론은 컨텐츠 기반 추천(Contents-based recommendation)이라고 한다. 사용자가 본/읽은 것과 유사한 컨텐츠를 찾아서 추천해주는 기법으로 유사도(similarity)가 높은 컨텐츠를 찾아내는 방식이다. 이 과정에서 컨텐츠를 벡터화(Vectorization)하여 유사도를 측정한다.

출처 : http://www.sbr.ai/news/articleView.html?idxno=1582 

 

유클리디안 유사도

 유클리디안 유사도 문서간의 유사도를 계산하는 가장 기본적인 방식이다. p 벡터와 q 벡터의 거리를 구하는 것으로 우리가 중학교 때 배웠던 2차원의 피타고라스 정리를 생각하면 쉽게 이해할 수 있다. (피타고라스 정리는 90도 직각인 경우에 성립하므로 2pq는 0이므로 아래 공식이 성립한다.) 

 

유클리디안 유사도 사례

 우선 가상의 문서 4개를 생성하고 사이킷런에서 CounterVectorizer 모듈을 임포트 한다.

docs = [
  '토마스가 가고 싶은 나라는 콜롬비아', # 문서0 
  '루나가 가고 싶은 나라는 포르투갈', # 문서1
  '살사와 바차타의 국가 콜롬비아 비바 콜롬비아', # 문서2 
  '루나는 그래도 포르투갈이 좋아요' # 문서3 
]

from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer() # Counter Vectorizer 객체 생성

 각 문장을 벡터로 변형하는데 각 문장에 쓰인 단어를 카운트한다. '가고'는 0번에 '포르투갈이'는 14번에 부여된다.

# 문장을 Counter Vectorizer 형태로 변형 
countvect = vect.fit_transform(docs) 
countvect # 4x9 : 4개의 문서에 9개의 단어 

# toarray()를 통해서 문장이 Vector 형태의 값을 얻을 수 있음 
# 하지만, 각 인덱스와 컬럼이 무엇을 의미하는지에 대해서는 알 수가 없음 
countvect.toarray()

vect.vocabulary_

sorted(vect.vocabulary_)

 

  데이터프레임으로 이쁘게 변환하여 벡터화한다.

import pandas as pd
countvect_df = pd.DataFrame(countvect.toarray(), columns = sorted(vect.vocabulary_))
countvect_df.index = ['문서1', '문서2', '문서3', '문서4']
countvect_df

 

 육안으로 보면 문서 0과 문서 1이 유사도 0.5로 유사도가 가장 높아보인다. 문서 n과 문서 n은 유사도가 1이지만 시각화 할 때 방해가 되서 그냥 일괄적으로 0을 입력하였다.

from sklearn.metrics.pairwise import euclidean_distances
euclidean_distances(countvect_df, countvect_df) # 벡터간의 유클리디안 거리

#eculidean_similarity = 1 / (euclidean_distances(countvect_df, countvect_df)+1e-5) 
# 1e-5(0.00001) 를 더해주는 이유는 분모가 0이 되는 것을 방지하기 위해서임
# 유클리디안 유사도 = 1 / (유클리디안 거리 + 1e-05)

eculidean_similarity = 1 / (euclidean_distances(countvect_df, countvect_df)+1e-5) 
eculidean_similarity

# 동일 문서인 경우 유사도를 0으로 바꿈
# 1e-5 를 더하면서 유사도가 0인데 10000으로 나옴

df_similarity = pd.DataFrame(eculidean_similarity)

df_similarity

for n in range(len(df_similarity)):
  df_similarity.iloc[n][n] = 0

df_similarity

 

 이쁘게 시각화도 해보면 아래와 같다. 문서 0과 문서 1의 유사도가 가장 진한 녹색으로 표시된다.

import seaborn as sns
import matplotlib.pyplot as plt
ax = sns.heatmap(df_similarity, annot=True, annot_kws=dict(color='w'), cmap='Greens')
plt.show()

 

 

 그냥 육안으로 확인해도 문서 0과 문서 1의 문장이 가장 유사해보인다.

 '토마스가 가고 싶은 나라는 콜롬비아'# 문서0 
 '루나가 가고 싶은 나라는 포르투갈'# 문서1
 '살사와 바차타의 국가 콜롬비아 비바 콜롬비아'# 문서2 
 '루나는 그래도 포르투갈이 좋아요' # 문서3 

 

반응형

댓글