Search
Duplicate
📟

다양한 유사도 계산 이해하기

Created
2022/08/03
Editor
안녕하세요. 에디터 준희, 헤나입니다.
길을 가다가 가판대에서 귀여운 인형을 보았습니다. 불현듯 떠오른 한 친구! 그런데 왜 하필 그 친구가 떠올랐을까요? 친구가 인형이랑 비슷하게 생겨서, 아니면 그 인형을 좋아해서?
매번 콕 집어 이유를 말할 수는 없어도 사람은 몇 가지 근거에 기반해 아이템을 추천하곤 합니다. 컴퓨터도 별반 다르지 않은데, 훨씬 명시적이라는 차이점은 있습니다. 두 아이템 사이에 명확하게 어떤 특징이, 얼마만큼의 ‘유사도’를 갖고 있어서 사용자에게 아이템을 추천한다는 점이 분명합니다. 유사도란 두 데이터가 얼마나 같은지를 나타내는 척도입니다. 데이터를 어떤 공간의 좌표(위치)처럼 벡터화했을 때는, 두 데이터 사이의 거리를 유사도라고 부릅니다. 컴퓨터는 다양한 방법으로 아이템 벡터의 유사도를 계산합니다.
이번 시간에는 컴퓨터가 수행하는 다양한 유사도의 계산 방식을 이해해 볼게요.
오늘의 이야기 0. 유사도란? 1. 평균제곱차이 유사도 2. 코사인 유사도 3. 피어슨 유사도

0. 유사도란?

앞에서 말씀드린 것처럼 유사도는 두 데이터 사이의 거리를 뜻합니다. 유사도를 거리로 나타내기 전에, 두 데이터를 벡터로 변환하는 과정을 거쳐야 합니다. 여기서 벡터란 공간에서 크기와 방향을 가지는 값을 의미하며, 숫자 값의 나열로 표현됩니다. 예를 들어 어떤 영화 X, Y와 Z가 있다고 해볼까요. 이 영화들의 특징을 벡터로 나타내보겠습니다. 영화를 분류할 특징은 다양하지만, 그 중에서도 개봉 연도, 등급, 러닝타임, 제작 국가로 분류해 볼게요.
X = [1, 3, 6, 2]
Y = [2, 3, 0, 1]
Z = [3, 1, 5, 2]
(지정된 숫자는 아무 의미가 없습니다. 표현에 주목해주세요!)
사실 데이터를 벡터로 변환하는 과정은 예시처럼 수동으로 숫자를 찍는 게 아니라 미리 훈련된 모델을 사용하는 등의 방법으로 이루어집니다. 그렇게 변환된 벡터는 공간에서 위치의 기능을 하게 되고, 컴퓨터는 이 데이터들의 위치를 이용해 서로의 거리를 계산해서 유사도를 측정합니다. 한 가지 유의할 것은, 거리는 작을수록 유사하지만, 유사도는 클수록 유사하다는 점입니다.
유사도를 측정하기 위해서는 두 가지를 중요하게 생각해야 합니다. 첫 번째는 어떤 값을 이용해 유사도를 측정할 것인지, 즉 어떤 특징으로 데이터를 분류할 것인지를 고민해야 한다는 것입니다.
예를 들어 앞서 언급했던 영화를 분류해 보자면… 시청자의 선호도를 조사하기 위해 영화 X, Y와 Z를 벡터로 표현한다고 할 때, 위에서 나눴던 개봉 연도, 등급과 같은 단순한 분류만으로는 부족한 느낌이 있습니다. 선호도를 파악해야 하니 관객 수로 영화를 분류하는 것도 중요하고, 실제 시청자가 매긴 평점을 기준으로 분류하는 것도 중요하겠습니다.
이외에도 장르별, 시청 등급별 등 영화를 분류하는 기준은 아주 다양합니다. 그중 무엇을 선택할지는 항상 조사의 목적에 달려있습니다. 목적이 무엇인지 분명하게 파악하고 있어야 엉뚱한 분류로 시간을 낭비하지 않게 되겠죠.
두 번째로 중요하게 생각해야 하는 것은 어떤 방법을 이용해서 유사도를 계산할지입니다. 벡터화된 데이터 간의 유사도를 어떤 알고리즘을 이용해 계산할지를 고민해 봐야 한다는 것인데요. 여러 가지 방식이 있는데, 이번 글에서 다룰 내용은 평균 제곱 차이, 코사인 유사도, 피어슨 유사도 계산 방식입니다. 하나씩 차근차근 이해해 볼게요.

1. 평균제곱차이 유사도

평균제곱차이 유사도(Mean Squared Difference Similarity)는 동일한 항목에 대한 두 평가치의 차이를 제곱한 후 평균값을 내는 방식입니다. 한 아이템과 그 아이템을 평가한 두 사용자, 혹은 한 사용자와 그 사용자가 평가한 두 아이템의 관계를 나타내는 것이죠. 식을 통해 더 자세히 알아볼까요?
사용자 기반 협업 필터링과 아이템 기반 협업 필터링에서의 사용 예시를 보여드릴게요. 기본 계산 방식은 동일하기 때문에 사용자 기반 협업 필터링에서 자세히 설명해 드리고 아이템 기반 협업 필터링은 간단하게 설명하겠습니다.
사용자 u, v 사이의 평균제곱차이 유사도
MSD(u,v)=1IuviIuv(ruirvi)2MSD(u,v) = {1\over |I_{uv}|} \cdot \sum_{i \in I_{uv}} (r_{ui}-r_{vi})^2
**동일한 아이템은 아이템 i로, 두 사용자는 사용자 u, 사용자 i로 표현합니다.
1단계: 우선 같은 아이템에 대한 사용자 간의 평균제곱차이(MSD)부터 계산을 해줍니다.
맨 오른쪽부터 차근차근 식을 분석해보겠습니다.
(ruirvi)2(r_{ui} - r_{vi})^2
iIuv(ruirvi)2\sum_{i \in I_{uv}}(r_{ui} - r_{vi})^2
1IuviIuv(ruirvi)2{1\over |I_{uv}|} \cdot \sum_{i \in I_{uv}} (r_{ui}-r_{vi})^2
2단계: 이제 평균제곱차이(MSD) 유사도를 계산해줍니다.
msd_sim(u,v)=1msd(u,v)+1msd\_sim(u,v) = {1 \over msd(u,v) + 1}
아무래도 유사도는 두 벡터의 차이의 크기가 작을수록 크겠죠? 그래서 평균제곱차이(MSD)의 역수를 취한 것이 평균제곱차이 유사도입니다! 생각보다 간단하죠?
분모에 1을 더하는 것은 분모가 0이 되는 경우를 방지하기 위한 것이에요.
아이템 i, j 사이의 평균제곱차이 유사도
msd(i,j)=1UijuUij(ruiruj)2msd(i,j) = {1 \over {|U_{ij}|}} \cdot \sum_{u \in U_{ij}}(r_{ui} - r_{uj})^2
**동일한 사용자를 사용자 u로, 사용자가 평가한 두 아이템을 아이템 i, 아이템 j로 표현합니다.
사용자 u, v 사이의 평균제곱차이 유사도의 경우에서 자세히 설명 드렸듯이 사용자 u가 아이템 i에 부여한 평가치 ruir_{ui}, 아이템 j에 부여한 평가치 rujr_{uj}의 차이를 제곱하여, 아이템 모두를 평가한 사용자의 수를 나누어주어 평균제곱차이(MSD)를 계산해준 후 마지막으로 평균제곱차이(MSD) 유사도를 계산해주면 됩니다!
msd_sim(i,j)=1msd(i,j)+1msd\_sim(i,j) = {1 \over msd(i,j) + 1}

2. 코사인 유사도

다음은 코사인 유사도(Cosine Similarity)에 대해 설명드릴게요. 코사인 유사도는 두 벡터의 사잇각으로 유사도를 측정하는 방법입니다. 코사인 유사도 값이 1에 가까울수록 두 벡터가 서로 유사하다고 판단하죠. 여기서 말하는 벡터는 숫자의 나열로써, 만약 두 사용자간의 코사인 유사도를 구하고자 하면 각 사용자가 아이템에 부여한 평점들을 사용자1 벡터={4, 5, 3, 1, 2, 5}, 사용자2 벡터={2, 3, 5, 4, 3, 1} 로 두고 코사인 유사도 공식을 이용하여 유사도를 계산하는 것이랍니다.
similarity=cos(θ)=ABAB=i=1nAiBii=1nAi2i=1nBi2similarity = cos(\theta) = \frac {{A} \cdot {B}} {\lVert A \rVert \lVert B \rVert} = \frac {\sum\limits_{i=1}^{n} A_{i} B_{i}} {\sqrt{\sum\limits_{i=1}^{n} A_{i}^2} \sqrt{\sum\limits_{i=1}^{n} B_{i}^2}}
공식은 이렇습니다.
공식 증명은 크게 중요하지 않기 때문에 설명 생략할게요. 궁금하신 분들은 아래 링크 들어가시면 자세히 설명되어 있습니다!
위 공식을 이용하여 코사인 유사도를 계산하면 -1에서 1 사이의 값이 나오는데, -1은 서로 방향이 완전히 반대인 경우, 0은 두 벡터가 서로 독립적인 경우, 그리고 1은 서로 완전히 같은 경우를 의미합니다.
사용자 u, v 사이의 코사인 유사도
cosine_sim(u,v)=iIuvruirviiIuvrui2iIuvrui2cosine\_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_{ui}^2}}}
아이템 i, j 사이의 코사인 유사도
cosine_sim(i,j)=uUijruirujuUijrui2uUijruj2cosine\_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}}}
사용자의 평점 이외에도 텍스트에 코사인 유사도를 적용해 유사도를 계산하는 방식도 있습니다. 예를 들어 영화에 대한 줄거리를 모두 취합하여 각각의 줄거리에 나온 단어들과 표현들을 통해 다른 영화들에 비슷한 단어나 표현들이 얼마나 많이 나오는지에 따라 유사도를 계산하는 것이죠.
이 방식은 자연어 처리와 더 관련 있기 때문에 궁금하신 분들을 위해 밑에 링크만 첨부해둘게요!
코사인 유사도는 다양한 차원에서의 유사도를 잘 나타낼 수 있다는 장점이 있지만, 치명적인 단점들도 존재합니다.
1. 평점에 큰 차이가 있음에도 높은 유사도
예를 들어 고려되는 두 평점 벡터가 {1,1,1}과 {5,5,5}라면, 첫번째 평점 벡터는 가장 낮은 점수를 모두에 부여하고 두번째 평점 벡터는 가장 높은 점수를 모두에 부여하여 상반된 선호도에도 코사인 유사도는 사잇각을 가지고 유사도 판단을 하기 때문에 둘의 코사인 유사도 결과는 1이 나옵니다.
2. 차원이 적을 때 잘못된 유사도
두 사용자가 공통으로 평점을 부여한 아이템이 하나밖에 없는 상황에서는 1차원이 되는데, 1차원에서는 두 평점이 직선상에 놓이기 때문에 사잇각이 0도가 되어 코사인 유사도가 1이 나오게 됩니다.
Multi-reference Cosine: A New Approach to Text Similarity Measurement in Large Collections 논문에서는 다음과 같이, 평균제곱차이 유사도보다는 코사인 유사도가 정확도가 더 높다고 하였는데요,
“Generally, cosine text similarity measure has better recall and precision than most of other text similarity measures like Pearson Correlation Coefficient (PCC), Jaccard or Mean Square Difference (MSD) according to this research”
어느 방식이 더 정확하고 성능이 좋은지는 상황에 따라 다르겠죠?

3. 피어슨 유사도

마지막으로 다룰 유사도 계산 방식은 피어슨 유사도(Pearson Similarity) 계산입니다. 피어슨 유사도는 두 벡터의 상관계수(Pearson correlation coefficient)를 뜻합니다. 여기서 상관계수란 두 변수 간에 선형 관계의 정도를 수량화하는 척도입니다. 간단하게 말씀드리면 두 변수의 관계가 가상의 선에 얼마나 밀접하게 닿아 있는지를 알려주는 수치입니다. 그림과 같이 볼게요.
선형 관계 (출처: https://nittaku.tistory.com/456)
그림처럼 가장 직선처럼 생겼는데 위로 올라가는 방향성을 보일 때, 이를 양의 상관관계를 가진다고 하며 상관 계수는 1입니다. 한 변수가 특정한 방향(+)으로 움직이면, 다른 변수도 그쪽을 향해 따라가는 관계를 맺는다는 의미입니다. 반대로 상관 계수가 -1인 경우에는 두 변수가 반대로 변화한다고 보면 되겠죠. 상관 계수가 0일 때는 어떨까요? 이때는 두 변수가 독립적으로 움직여서, 한 변수로 다른 변수의 변화를 예측하지 못하는 관계가 됩니다.
상관 계수는 두 변수의 관계가 ‘얼마나 직선 같은지’를 나타내는 수치입니다. 직선처럼 생겼으면 -1이나 +1에 가깝게, 반대로 직선의 형태가 거의 없으면 어떤 모양이더라도 0에 가까운 상관 계수를 갖습니다. 덧붙여 직선은 양/음의 관계에 있는 것만 중요하지 얼마나 기울어졌는지, 30도인지 60도인지는 중요하지 않아요.
피어슨 상관계수를 접하기 전에 먼저 공분산의 개념을 이해해야 하는데요, 단어에 들어있는 분산의 개념부터 알아볼까요. 분산이란 집단 내에서 평균을 기준으로 자료들이 얼마나 떨어져 있는지, 즉 흩어져있는 정도를 나타내는 값입니다.
분산
S2=1Ni=1N(xixˉ)2S^2 = \frac{1} {N} \sum_{i=1}^N (x_{i} - \bar{x})^2
S2S^2 : 분산
xix_{i} : 모집단 X 내의 자료
xˉ\bar{x} : 모집단 X의 평균
그림처럼 측정할 자료의 값을 평균에서 빼고 제곱한 뒤 모두 더해서 모든 자료의 개수(N)로 나누면, 자료가 평균에서 얼마나 흩어져 있는지를 나타낼 수 있게 됩니다. 많이 흩어져 있을수록 값이 커지겠죠.
그런데 집단의 모든 자료를 가지고 분산을 계산하면 많은 시간이 듭니다. 그래서 집단 내의 표본, 즉 일부만을 가지고 와서 분산을 계산하는데요. 이를 표본분산이라고 부르며 식은 다음과 같습니다.
표본분산
S2=1n1i=1N(xixˉ)2S^2 = \frac {1} {n-1} \sum_{i=1}^N (x_{i} - \bar{x}) ^2
S2S^2 : 표본분산
xix_{i} : 표본집단 X 내의 자료
xˉ\bar{x} : 표본집단 X의 평균
모집단의 분산과 같은 방식으로 계산했으니 당연히 N(표본의 개수)으로 나눠야 할 텐데, 왜 n-1로 나누고 있을까요? 만약 모집단과 같은 방법으로 N으로 나누게 되면, 이 값들이 ‘표본’이라는 의미가 없어집니다. 표본집단은 말 그대로 일부의 집단인데 이를 전체 집단으로 착각해서 분산을 내면, 나머지 데이터가 전부 포함된 모집단과는 다른 결과를 내게 되겠죠. 데이터의 개수가 적어서 모집단보다는 분산이 작아지게 됩니다. 더 몰려있다고 판단하는 것이죠.
n 대신에 n-1로 나누면 한쪽으로 쏠린 것처럼 표현된, 작아진 표본분산의 크기를 키울 수 있게 됩니다. 과소평가된 표본분산을 의도적으로 키워서 모집단의 흩어진 정도와 값을 맞춰주려고 하는 것이라고 볼 수 있겠습니다.
분산은 전체가 흩어진 정도를 계산하는 과정이었죠. 이번에는 공분산의 개념을 정리해 볼게요. 공분산의 은 여럿이, 함께를 의미합니다. 위에서 봤던 분산처럼 한 집단(X) 내에서 데이터들의 흩어진 정도를 나타내는 것이 아니라 두 집단이 같은 방향으로 움직이는 정도, 서로 얼마나 흩어져 있는지를 나타내는 값이라는 뜻입니다. 수식과 함께 볼게요.
공분산
σxy=1Ni=1N(xiμx)(yiμy)\sigma_{xy} = \frac {1} {N} \sum_{i=1}^N (x_{i} - \mu_{x}) (y_{i} - \mu_{y})
σxy>0\sigma_{xy}>0 : X와 Y가 양의 선형 관계
σxy<0\sigma_{xy}<0 : X와 Y가 음의 선형 관계
σxy=0\sigma_{xy}=0 : X와 Y는 선형적 관계를 갖지 않음
식에서 μ\mu는 분산에서와 마찬가지로 평균입니다. 분산을 구하는 식과 매우 비슷하죠. 집단 X의 자료에서 평균을 빼준 값과 집단 Y의 자료에서 평균을 빼준 값을 곱한 뒤에 모든 자료의 개수(N)로 나누면 공분산을 구할 수 있게 됩니다. 여기서도 마찬가지로, 두 집단의 전체 자료가 아니라 표본을 이용해서 공분산을 구합니다. n-1로 나눠야겠죠!
표본 공분산
Sxy=i=1n(xixˉ)(yiyˉ)n1S_{xy} = \frac {\sum\limits_{i=1}^{n} (x_{i} - \bar{x}) (y_{i} - \bar{y})} {n-1}
공분산은 두 변수 사이의 관계를 보여주기는 하지만 측정 단위에 영향을 받는다는 단점이 있습니다. 예를 들어 100점 만점인 두 과목과 10점 만점인 두 과목의 공분산을 각각 구한다고 할게요. 각 그룹에서 유사도가 같은 과목끼리 비교했다고 하더라도 전자의 공분산이 더 크게 계산됩니다. 단위에 의해 숫자의 절대적인 크기가 달라지면 공분산의 값도 달라지는 것이죠.
이를 보완하기 위해 이번 챕터의 핵심인 피어슨 상관계수를 유사도 측정에 이용합니다.
피어슨 상관계수
ρxy=σxyσxσy=i=1n(xixˉ)(yiyˉ)i=1n(xixˉ)2i=1n(yiyˉ)2\rho_{xy} = \frac{\sigma_{xy}} {\sigma_{x} \sigma_{y}} = \frac {\sum\limits_{i=1}^n (x_{i} - \bar{x}) (y_{i} - \bar{y})} {\sqrt{\sum\limits_{i=1}^n (x_{i} - \bar{x})^2 \sum\limits_{i=1}^{n} (y_{i} - \bar{y})^2 }}
분자에 있는 편차를 그 크기로 나누면 단위는 더 이상 문제가 되지 않겠죠. 100점 만점이든, 10점 만점이든 피어슨 상관계수는 -1에서부터 1 사이의 값을 가집니다. 상관계수를 처음 다룰 때 그래프를 몇 개 보여드렸었죠. 같은 의미로 -1, 1에 가까우면 직선의 형태를, 0에 가까우면 직선이 아닌 형태를 띠게 된다고 이해하시면 되겠습니다.
이제 추천 시스템에 피어슨 유사도를 적용한 것을 보여드릴게요. 개념은 위의 식과 같아서 생략하겠습니다.
사용자 u, v 사이의 피어슨 유사도
pearson_sim(u,v)=iIuv(ruiμu)(rviμv)iIuv(ruiμu)2iIuv(rviμv)2pearson\_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}}}
μu\mu_{u}, μv\mu_{v} : 사용자 u, v의 평균 평점
아이템 i, j 사이의 피어슨 유사도
pearson_sim(i,j)=uUij(ruiμi)(rujμj)uUij(ruiμi)2uUij(rujμj)2pearson\_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}}}
μi\mu_{i}, μj\mu_{j} : 상품 i, j의 평균 평점
마지막으로 각 유사도가 코드로 어떻게 쓰이는지 궁금하신 분들은 밑의 링크를 참조해 주세요!
오늘은 유사도의 개념과 함께 추천 시스템에서 사용되는 여러가지 유사도 계산 방식들: 평균제곱차이 유사도, 코사인 유사도, 피어슨 유사도에 대해 배우고 직접 파이썬으로 구현까지 해보았는데 어떠셨나요? 공식이 많아서 최대한 이해하기 쉽게 차근차근 설명드리려 최선을 다했는데 잘 이해하셨길 바라요 유사도 계산은 고객 개개인에 딱 맞춰진 추천을 해주는 데에 굉장히 중요한 역할을 하기 때문에 앞으로 추천 시스템에 대해 공부하거나 직접 시스템을 구축하게 될 때 많은 도움이 될거라 생각합니다. 다음에도 유익하고 재미있는 글로 찾아뵐게요 ~ :)