온라인 강의 자료모음 기업교육

유사도(Similarity) 계산 방식

이해하기 쉽고, 장황하지 않은 자료를 기반으로 강의를 진행합니다.
AI · 풀스택 · 데이터 로드맵 Dave Lee 한 강사가 설계부터 강의까지 모두
사이트 바로가기

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$ 모두를 평가한 사용자의 수

Mean Squared Difference Similarity

데이터 분석 기초를 체계적으로 익힐 수 있는 온라인 강의입니다

처음하는 파이썬 데이터 분석

pandas, plotly 시각화, 데이터 전처리 기본

  • 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} $$

In [15]:
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) )
In [16]:
sim_msd(ratings, 'Dave','Alex')
Out[16]:
0.2857142857142857
Dave와 Andy의 msd 유사도 구하기
In [17]:
sim_msd(ratings, 'Dave','Andy')
Out[17]:
0.15

데이터 분석/과학 전문가가 되기 위한 체계적인 로드맵입니다

가장 빠른 데이터 분석/과학 풀로드맵 (2025)

데이터 수집 → 분석 → 머신러닝/딥러닝 전과정

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: 두 사용자가 모두 평가한 상품의 평점을 사용해서 계산
$$ \text{cosine_sim}(u, v) = \frac{ \sum\limits_{i \in I_{uv}} r_{ui} \cdot r_{vi}} {\sqrt{\sum\limits_{i \in I_{uv}} r_{ui}^2} \cdot \sqrt{\sum\limits_{i \in I_{uv}} r_{vi}^2} }$$
  • 상품 $i$와 상품 $j$간의 Cosine Similarity: 두 상품의 평점을 사용해서 계산
$$ \text{cosine_sim}(i, j) = \frac{ \sum\limits_{u \in U_{ij}} r_{ui} \cdot r_{uj}} {\sqrt{\sum\limits_{u \in U_{ij}} r_{ui}^2} \cdot \sqrt{\sum\limits_{u \in U_{ij}} r_{uj}^2} } $$

참고: 스칼라곱 - 두 벡터로 스칼라를 계산하는 연산

풀스택 개발자가 되기 위한 체계적인 로드맵입니다

가장 빠른 풀스택 개발 로드맵 (2025)

파이썬 → Flask → FastAPI → Flutter 전과정

두 벡터 의 스칼라곱(두 벡터로 스칼라를 계산하는 연산)은 다음과 같다:

이를 다음과 같이 코사인 함수를 사용해서도 표현함

In [18]:
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))
In [19]:
sim_cosine(ratings, 'Dave','Alex')
Out[19]:
0.9938837346736189

데이터 분석 기초를 체계적으로 익힐 수 있는 온라인 강의입니다

처음하는 파이썬 데이터 분석

pandas, plotly 시각화, 데이터 전처리 기본

Dave와 Cosine Similarity를 사용해서 가장 유사한 사용자는?
In [20]:
sim_cosine(ratings, 'Dave','David')
Out[20]:
0.8319479070496523
In [21]:
sim_cosine(ratings, 'Dave','Andy')
Out[21]:
0.7795844649455863

3.3. 피어슨 유사도 (Pearson Similarity)

피어슨 유사도는 두 벡터의 상관계수(Pearson correlation coefficient)를 의미

피어슨 유사도는 유사도가 가장 높을 경우 값이 1, 가장 낮을 경우 -1의 값을 가짐

특정인물의 점수기준이 극단적으로 너무 낮거나 높을 경우 유사도에 영향을 크게 주기 때문에, 이를 막기 위해 상관계수를 사용하는 방법

  • 사용자 $u$와 사용자 $v$간의 Pearson Similarity
$$ \text{pearson_sim}(u, v) = \frac{ \sum\limits_{i \in I_{uv}} (r_{ui} - \mu_u) \cdot (r_{vi} - \mu_{v})} {\sqrt{\sum\limits_{i \in I_{uv}} (r_{ui} - \mu_u)^2} \cdot \sqrt{\sum\limits_{i \in I_{uv}} (r_{vi} - \mu_{v})^2} } $$

$\mu_u$는 사용자 $u$의 평균 평점

  • 상품 $i$와 상품 $j$간의 Pearson Similarity
$$ \text{pearson_sim}(i, j) = \frac{ \sum\limits_{u \in U_{ij}} (r_{ui} - \mu_i) \cdot (r_{uj} - \mu_{j})} {\sqrt{\sum\limits_{u \in U_{ij}} (r_{ui} - \mu_i)^2} \cdot \sqrt{\sum\limits_{u \in U_{ij}} (r_{uj} - \mu_{j})^2} } $$

$\mu_i$는 상품 $i$의 평균 평점

데이터 분석/과학 전문가가 되기 위한 체계적인 로드맵입니다

가장 빠른 데이터 분석/과학 풀로드맵 (2025)

데이터 수집 → 분석 → 머신러닝/딥러닝 전과정

In [22]:
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))
In [23]:
sim_pearson(ratings, 'Dave','Alex')
Out[23]:
0.970142500145332
In [24]:
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]
In [25]:
top_match(ratings, 'Dave', 3)
Out[25]:
[(0.970142500145332, 'Alex'),
 (0.5406205059012895, 'David'),
 (0.39840953644479793, 'Andy')]
top_match를 사용해서 Alex와 가장 유사한 사용자는?

풀스택 개발자가 되기 위한 체계적인 로드맵입니다

가장 빠른 풀스택 개발 로드맵 (2025)

파이썬 → Flask → FastAPI → Flutter 전과정

In [26]:
top_match(ratings, 'Dave', 3, sim_function=sim_msd)
Out[26]:
[(0.2857142857142857, 'Alex'), (0.1764705882352941, 'David'), (0.15, 'Andy')]
In [27]:
top_match(ratings, 'Dave', 3, sim_function=sim_cosine)
Out[27]:
[(0.9938837346736189, 'Alex'),
 (0.8319479070496523, 'David'),
 (0.7795844649455863, 'Andy')]
In [28]:
top_match(ratings, 'Dave', 3, sim_function=sim_pearson)
Out[28]:
[(0.970142500145332, 'Alex'),
 (0.5406205059012895, 'David'),
 (0.39840953644479793, 'Andy')]