유사도(Similarity) 계산 방식
3. 유사도(Similarity) 계산 방식¶
3.1. 평균제곱차이 유사도 (Mean Squared Difference Similarity)
3.2. 코사인 유사도 (Cosine Similarity)
3.3. 피어슨 유사도 (Pearson Similarity)
3.1. 평균제곱차이 유사도 (Mean Squared Difference Similarity)¶
Mean Squared Difference¶
- User-based Collaborative Filter 경우: 사용자 $u$와 사용자 $v$간의 msd
사용자 $u$와 사용자 $v$가 평가한 상품들의 평점간의 차의 제곱 / 사용자 $u$와 사용자 $v$가 모두 평가한 상품들의 수
$$ \text{msd}(u, v) = \frac{1}{|I_{uv}|} \cdot \sum\limits_{i \in I_{uv}} (r_{ui} - r_{vi})^2 $$
- $I_{uv}$는 사용자 $u$와 사용자 $v$ 모두에 의해 평가된 상품의 집합
- $|I_{uv}|$는 사용자 $u$와 사용자 $v$ 모두에 의해 평가된 상품의 수
- Item-based Collaborative Filter 경우: 상품 $i$와 상품 $j$간의 msd $$ \text{msd}(i, j) = \frac{1}{|U_{ij}|} \cdot \sum\limits_{u \in U_{ij}} (r_{ui} - r_{uj})^2 $$ 위 식에서 $U_{ij}$는 상품 $i$와 상품 $j$ 모두를 평가한 사용자의 집합이고 $|U_{ij}|$는 상품 $i$와 상품 $j$ 모두를 평가한 사용자의 수
- $I_{uv}$는 사용자 $u$와 사용자 $v$ 모두에 의해 평가된 상품의 집합
Mean Squared Difference Similarity¶
- Mean Squared Difference (msd) 의 역수로 계산
- 차이가 클 수록 Similarity 값은 작아진다!
- Mean Squared Difference Similarity 식에서는 MSD가 0이 되는 경우를 대응하기 위해 1을 무조건 더해줌
$$ \begin{split}\text{msd_sim}(u, v) &= \frac{1}{\text{msd}(u, v) + 1}\\ \text{msd_sim}(i, j) &= \frac{1}{\text{msd}(i, j) + 1}\end{split} $$
def sim_msd(data, name1, name2):
sum = 0
count = 0
for movies in data[name1]:
if movies in data[name2]: #같은 영화를 봤다면
sum += pow(data[name1][movies]- data[name2][movies], 2)
count += 1
return 1 / ( 1 + (sum / count) )
sim_msd(ratings, 'Dave','Alex')
sim_msd(ratings, 'Dave','Andy')
3.2. 코사인 유사도 (Cosine Similarity)¶
코사인 유사도(Cosine Similarity)는 두 특성 벡터간의 유사 정도를 코사인 값으로 표현한 것임
Cosine Similarity는 −1에서 1까지의 값을 가지며, −1은 서로 완전히 반대되는 경우, 0은 서로 독립적인 경우, 1은 서로 완전히 같은 경우를 의미함
$$ x \cdot y = |x| |y| \cos\theta $$$$ \cos\theta = \dfrac{x \cdot y}{|x| |y|}$$
이를 사용하여 Consine Similarity를 적용하면
- 사용자 $u$와 사용자 $v$간의 Cosine Similarity: 두 사용자가 모두 평가한 상품의 평점을 사용해서 계산
- 상품 $i$와 상품 $j$간의 Cosine Similarity: 두 상품의 평점을 사용해서 계산
참고: 스칼라곱 - 두 벡터로 스칼라를 계산하는 연산¶
두 벡터 의 스칼라곱(두 벡터로 스칼라를 계산하는 연산)은 다음과 같다:
이를 다음과 같이 코사인 함수를 사용해서도 표현함
import math
def sim_cosine(data, name1, name2):
sum_name1 = 0
sum_name2 = 0
sum_name1_name2 = 0
count = 0
for movies in data[name1]:
if movies in data[name2]: #같은 영화를 봤다면
sum_name1 += pow(data[name1][movies], 2)
sum_name2 += pow(data[name2][movies], 2)
sum_name1_name2 += data[name1][movies]*data[name2][movies]
return sum_name1_name2 / (math.sqrt(sum_name1)*math.sqrt(sum_name2))
sim_cosine(ratings, 'Dave','Alex')
sim_cosine(ratings, 'Dave','David')
sim_cosine(ratings, 'Dave','Andy')
3.3. 피어슨 유사도 (Pearson Similarity)¶
피어슨 유사도는 두 벡터의 상관계수(Pearson correlation coefficient)를 의미
피어슨 유사도는 유사도가 가장 높을 경우 값이 1, 가장 낮을 경우 -1의 값을 가짐
특정인물의 점수기준이 극단적으로 너무 낮거나 높을 경우 유사도에 영향을 크게 주기 때문에, 이를 막기 위해 상관계수를 사용하는 방법
- 사용자 $u$와 사용자 $v$간의 Pearson Similarity
$\mu_u$는 사용자 $u$의 평균 평점
- 상품 $i$와 상품 $j$간의 Pearson Similarity
$\mu_i$는 상품 $i$의 평균 평점
def sim_pearson(data, name1, name2):
avg_name1 = 0
avg_name2 = 0
count = 0
for movies in data[name1]:
if movies in data[name2]: #같은 영화를 봤다면
avg_name1 = data[name1][movies]
avg_name2 = data[name2][movies]
count += 1
avg_name1 = avg_name1 / count
avg_name2 = avg_name2 / count
sum_name1 = 0
sum_name2 = 0
sum_name1_name2 = 0
count = 0
for movies in data[name1]:
if movies in data[name2]: #같은 영화를 봤다면
sum_name1 += pow(data[name1][movies] - avg_name1, 2)
sum_name2 += pow(data[name2][movies] - avg_name2, 2)
sum_name1_name2 += (data[name1][movies] - avg_name1) * (data[name2][movies] - avg_name2)
return sum_name1_name2 / (math.sqrt(sum_name1)*math.sqrt(sum_name2))
sim_pearson(ratings, 'Dave','Alex')
def top_match(data, name, index=3, sim_function=sim_pearson):
li=[]
for i in data: #딕셔너리를 돌고
if name!=i: #자기 자신이 아닐때만
li.append((sim_function(data,name,i),i)) #sim_function()을 통해 상관계수를 구하고 li[]에 추가
li.sort() #오름차순
li.reverse() #내림차순
return li[:index]
top_match(ratings, 'Dave', 3)
top_match(ratings, 'Dave', 3, sim_function=sim_msd)
top_match(ratings, 'Dave', 3, sim_function=sim_cosine)
top_match(ratings, 'Dave', 3, sim_function=sim_pearson)