카테고리 보관물: 알고리즘

Interpolation methods – 내간법

Interpolation methods (내간법)

용어 확인을 위해서 영어사전을 찾아 보시면 내간법/내삽법/보간법이라고 나옵니다.   뭔가 다소 괴기스러운 어감인데 (^^;) 보신적이 없다면 어감상으로는 뭔가 내부에서 간섭을 하거나 삽입하는 어떤것들이 연상될 것 같습니다.

내삽법 관련된 알고리즘을 찾다가 다시 당분간 이쪽분야를 할 일이 없어질 것 같아서 전에 찾아놓은 자료를 우선 아는데까지만 적어 놓으려고 합니다.
그래서 그냥 찾아 놓은 기법들 소개 정도입니다.

Interpolation(내간법)이라는 용어를 흔히 볼 수 있는 곳은

  1. 스크립트 랭귀지같은 것들중에 변수명을 문자열에 삽입해서 대치시키는 것.

    이것은 coercing 이라고도 하는데 용어가 좀 다양하게 쓰입니다. “blah $varialbe blah” 요런거입니다. PHP, Perl등의 언어에서 쉽게 볼 수 있는데 별로 중요하지 않습니다.

  2. 데이터 분석에서 관측되지 않은 지점의 데이터를 추정하는 방법

    당연히 이 포스트에서는 두번째입니다.

(아래 플롯 참조)

Ordinary Kriging

내간법은 관측치(Observation)가 없는 부분의 데이터를 관측치(Observation)를 이용해서 얼추 추정해서 때려 맞추는 것인데요. 대부분 현실적으로 관측을 모두 다 할 수 없어 중요한 부분만 관측하고 나머지는 추정을 해야 하는 경우에 쓰입니다.

세상은 우리의 상상만큼 그렇게 만만하지 않은 것 같아요. ^^

보통 공간통계(Geo-Spatial Analysis) 분야에서 쉽게 찾아 볼 수 있는데요.
활용에 대한 대략적인 예시는 이런 것들입니다.

  1. 전국의 모든 지점의 온도나 습도, 공기오염도 등을 다 측정할 수 없으므로 적당히 중간중간 중요한 지점을 측정하고 나머지는 보정해서 때려 맞출때

  2.  제조업등에서 불량 검사를 할 때 특정 판에서 온도 측정을 모두 할 수 없으므로 군데군데 하고 빈곳은 추정할 때

  3. 최근에는 IoT 스마트헬스케어 같은 곳에서 건물이나 집안의 온도나 습도에 대한 분포를 알고 싶은데 바닥에 센서를 죄다 깔아 놓을 수 없으니 적당한 곳만 측정하고 나머지는 때려 맞출때도 사용합니다.

    사실 이것 때문에 살펴보게 된 것입니다만 그래서 어떤 방법들이 있나 봤더니 굉장히 많더군요

Regression Model (회귀 모델)

회귀 모델도 내간법에 들어갑니다.

생각해보니 그러네요. 회귀 모델도 결국 관측치도 미관측 데이터를 추정하는 것이니 그쪽으로 보면 그 분류가 맞습니다.   단 공간분석에는 적합하지 않으니 쓰지 말라는 말도 있습니다. (물론 쓰는 사람들도 있습니다)

Kernel Density Estimation (커널밀도추정)

패턴 인식이나 기계 학습 책을 보셨거나 관련된 일을 하신다면 커브피팅(curve-fitting)이나 커널밀도추정에 대해서 보신적이 있을 텐데요.
이것도 내간법으로 넣습니다.
커널 밀도 추정은 다차원 공간에서 씨알(데이터)을 하나 이상 머금은 다차원 깍두기(커널)를 만들고 깍두기를 스무딩해서 매끄럽게 만들어 밀도를 추정하는 방법입니다.
보통 2차원, 3차원까지를 많이합니다. 히스토그램의 구체화된 형태라고 할 수 있습니다.   공간 분석에서도 사용하긴 하지만 많이 사용하지는 않는 것 같습니다.

Inverse Distance Weighted Interpolation

해석을 하면 많이 어색하지만 역거리내삽법 또는 거리 반비례 가중치 내삽법등으로 바꿀 수 있을텐데 보통 IDW라고 통칭합니다. GIS나 Geo-Spatial에서 흔히 볼 수 있는 내삽법입니다.   그냥 거리가 멀어질 수록 영향을 덜 받는다입니다.

Kriging (그리깅 격자법)

만든 사람이 이름이 Krige여서 Kriging라고 합니다.   크리깅 또는 그리깅이라고 읽는데 우리말의 김치의 ㄱ과 같은 발음인 것 같습니다. 이름도 이상하지만 이건 상당히 복잡한데요.   Spatial Analysis 책을 들여다보면 분산도(Variogram) 부터 공간자기상관(Spatial Autocorrelation) 같은 말부터 Semivariogram같은 비전문가에게는 무척 생소한 용어가 나오고 알고리즘을 따라 내려가다보면 결국 최적화 문제로 라그랑지 승법이 나옵니다.

성능이 굉장히 좋다고 알려져 있어서 대부분 GIS나 Geo-Spatial에서는 항상 언급이 됩니다. IDW보다는 수학적, 통계학적으로 기반 이론이 훨씬 그럴싸하기 때문에 굉장히 자주 사용하는데 역시 좋은 만큼 안쪽은 쉽게 설명하기에는 상당히 복잡합니다.

그리고 크리깅은 다시 Simple Kriging, Universal Kriging, Ordinary Kriging 등으로 나뉩니다.
보간법 중에는 Kriging이 끝판왕쯤 되는 것 같습니다.   추가로 크리깅은 예측값에 대한 에러를 추정하는 것이 가능하다고 되어 있습니다.  

조금 신기하네요. 요건 나중에 따로 정리를 시도해 보겠습니다. (너무 어려워서…)

보간법은 이외에도 무수히 많습니다. K-NN도 사용을 하구요 당췌 뭐가 뭔지 모를 정도로 많아서 혼란스러운데 역시 가끔은 다른 쪽에서는 뭘하고 있는지 살펴보는 것도 중요한 것 같습니다.

Cosine Similarity – 코사인 유사도

대부분의 과학기술에 대한 설명은 위키피디아에 다 설명이 되어 있습니다. 코사인 유사도 역시 위키피디아에도 설명이 잘 되어 있습니다. 하지만 위키피디아가 대부분 그렇듯이 조금 불친절한 감이 있습니다.

한국어 위키피디아 보다는 영문 위키피디아가 정리가 잘 되어 있습니다.  만약 위키피디아의 내용을 참고하실 것이면 영문위키피디아의 내용을 보는 것이 더 나을 것 같습니다.

이 포스트는 조금 쉽게 풀어서 설명하려다 보니 내용이 조금 깁니다. 그러니 시간 여유를 두고 보셔야 합니다.

코사인유사도는 대체 뭘까?

200px-Dot_Product.svg

위키피디아와는 상관없이 제 나름대로 코사인유사도를 설명하면
두 벡터(Vector)의 사잇각을 구해서 유사도(Similarity)로 사용하는 것을 말합니다.

이때 유사도를 구할 때 두 벡터 사이의 각을 코사인(Cosine)으로 구해서 유사도값으로 사용하기 때문에 코사인 유사도(Cosine Similarity)라고 부릅니다.

그게 전부입니다.

벡터의 유사도를 구하는 방법은 여러가지가 있습니다. 코사인 유사도는 그 중 하나입니다. 다른 것과는 다르게 코사인 유사도의 특징은 사잇각을 이용한다는 것입니다.

위에 간단한 그림이 있었습니다.   그림을 보시면
A와 B는 유사도를 계산할 두 벡터(vector, 또는 두개의 수열값 세트)이고 두 벡터의 A와 B의 사잇각 쎄타를 코사인으로 구하는 것이고 이 사잇각이 코사인 유사도로  사용합니다.

참고로 위의 그림에서 두 벡터는 2차원 벡터를 표현해 놓은 것입니다. 축이 2개있는 평면이니까요.  하지만 벡터는 2차원 이상의 고차 벡터가 더 많습니다.  즉 축이 더 많다고 생각하면 됩니다.  3차원까지는 입체이고 4차원 부터는 못 그립니다.

벡터의 차원에 대해서 잠깐 설명하고 넘어가면 10차원 벡터는 아래와 같습니다.

10차원의 두 벡터의 예:

  • A = 1,2,3,4,5,6,7,8,9,10
  • B = 2,3,4,5,6,7,8,9,10,11

A와 B는 각각 수열이고 각각 10개씩 숫자를 가지고 있으므로 10차원의 벡터입니다. 10차원 벡터는 눈으로 볼 수 있게 시각적으로 표현할 수 없습니다. 그 보다 숫자들이 하나씩 더 있으면 11차원이고 그렇습니다.

수학 수업에서 아마 배우셨겠지만 또는 잊어버리셨겠지만 (괜찮아요. 다들 그래요) 3차원까지는 시각적으로 표현이 가능하지만 4차원부터는 인간의 눈으로 볼 수 있게 시각적 표현은 불가합니다. 인간이 통제할 수 있는 차원이 3차원까지 이기 때문입니다. 그 이상은 머리속으로 추상적으로만 연상(imagination)을 하셔야 합니다.

하지만 2차원이든 100차원이든 시각적으로 표현이 불가해도 코사인 유사도는 정해진 공식으로 구할 수 있고 구하는 방법도 간단합니다.

실제로 구하는 풀이는 뒤에 설명드리겠습니다.

코사인 유사도의 용도

계산법을 보기전에 아마도 많은 분들이 궁금할 것이 “두 벡터의 유사도를 구해서 어디에 쓰는가?” 라는 것일텐데요. (선형대수학을 깊이 공부하지 않으셨거나 관심이 없으셨다면 그럴 것입니다). 이걸 알게 되면 사실 코사인 유사도를 이해하는 것이 더 쉽습니다.

우선 그전에

벡터는 무엇이고 유사도는 무엇인가?

라는 생각이 든다면  고교수학과정에서 배우신 것을 다 잊어버리셨거나 자체 검열로 기억에서 삭제하셨을 가능성이 큽니다. 어쨌든 이해를 위해서는 그것 부터 다시 복습하고 오셔야합니다. 기억하시는 분들이 이부분은 건너 뛰셔도 됩니다.

고등학교 수학책을 보면 두 벡터의 내각을 구하는 것으로 코사인 유사도가 이미 나와있습니다. 아마도 상당수의 분들은 배웠다는 얘기일 것입니다.  요즘은 선택에 따라서 건너 뛸 수도 있다고 하던데 저는 꽤 옜날 사람입니다.

전공이 공학이나 자연과학 계열이라면 대학에서는 대학수학, 공업수학이나 이산수학에도 초반부에 아주 가끔 나옵니다.  물론 대학교 교재같은 것에서는 공대생이여 “이쯤은 이미 다 알고 있지?”  라는 식으로 가볍게 나옵니다.  대략 반페이지만 설명하는 책도 많습니다.

이 부분을 가볍게 건너 뛰는 것은 이것을 설명하려면 벡터부터 설명을 해야하는데 그러면 너무 장황해지고 이미 고등학교에서 많은 시간동안 배웠다고 가정하기 때문입니다.

벡터는 원점에서 부터 어떤 방향을 가르키는 수의 열이라고 생각하시면 됩니다. 위에서 잠깐 설명드린 것 처럼 숫자가 1개 있으면 1차원벡터, 2개있으면 2차원 벡터, 100개면 100차원 벡터입니다.  물론 물리적으로 설명하면 조금 다르겠습니다만 그것까지는 안하겠습니다.

유사도는 비슷한지 아닌지를 나타내는 추상적인 개념이고 코사인 유사도에서의 유사도는 위에서 말씀드렸습니다. 유사도 또한 따로 포스팅을 해야 할 만큼 양이 방대합니다.  넘어갑니다.

코사인 유사도의 용도

코사인 유사도는 대충 다음과 같은 구체적인 용도가 있습니다.

  1. 검색 엔진에서 검색어(Query)와 문서(Document)의 유사도를 구해서 가장 유사도가 높은 것을 먼저 보여주기 위한 기본 랭킹 알고리즘으로 사용됩니다.
    그렇다고 검색 랭킹을 이것으로 다 하는 것은 아닙니다. 그냥  매우 기본으로 쓰이는 것입니다. 정보추출관련 책이나 자료를 찾아보시면 벡터 스페이스 모델 (Vector Space Model)에서 문서(Document)들간의 유사도를 구하기 위해서 쓴다고 되어 있을 것입니다.
    그래서 Consine Similarity(코사인 유사도)라고 말하면 문서의 유사도를 구한다고 대부분 생각하기 쉽습니다. 주로 거기에서 많이 등장하니까요. 하지만  꼭 거기에만 쓰이는 것은 아닙니다.
    정보검색이나 검색엔진과 관련이 깊어서  코사인유사도가 항상 TF-IDF(Term Frequency – Inverse Document Frequency)와 같이 언급되는 이유이기도 합니다.
  2. 그 외에도 다른 분석이나 모형에서도 유사도를 구할 때 사용합니다. 가끔 나옵니다만 흔하지는 않습니다. 이걸 사용해서 할 만한 것이 예상 외로 적습니다. 두 벡터의 유사도를 각으로 계산할 일이 있다면 쓰입니다. 문서에만 쓰이는 것은 아닙니다. 구체적인 예는 이제 생각이 잘 안납니다.  코사인유사도가 그렇게 다양하게 쓰이지는 않는 것 같습니다.
  3. 클러스터링(Clustering, 군집화) . 군집화 모델에서도 쓰이긴 합니니다. 비슷한 것을 묶기 위해서 거리를 구하는 것이 기본인데 벡터의 유사도를 추출하는데 쓰는 거리계산법의 하나입니다. 클러스터링을 모르시면 그냥 패쓰! 벡터 2개의 유사도를 구한다고 했지만 벡터 2개만 가지고는 유사도값이 하나만 나오기 때문에 아무짝에도 쓸모가 없습니다. 사실 2번과 같은 이유라고 보시면 됩니다.

*위의 1번의 검색 랭킹의 문제*

검색엔진이나 텍스트 마이닝에서 주로 쓰이는 이유는 문서를 숫자로 표현하는 방법중에 가장 쉽고 잘 알려진 방법이 포함된 단어들의 출현 횟수를 세고 그걸 숫자로 만드는 것이기 때문입니다.

검색엔진에서 흔히 비교할 문서들은 검색엔진의 검색창에 입력한 질의어(query라고 합니다)와 검색엔진이 가지고 있는 문서들을 비교해서 가장 비슷한 것을 찾기 때문입니다. 여기서 코사인 유사도를 구하는 대상이 사용자가 입력한 질의어와 검색엔진이 가지고 있는 모든 문서들과의 쌍입니다. 그렇게 해서 코사인 유사도를 구해서 가장 유사도가 큰 것을 가장 위에 보여줍니다. (현재의 검색엔진은 이렇게 단순하게 작동하지 않습니다. 오해를 방지하기 위해서 적어둡니다).

이때 검색엔진이나 텍스트마이닝에서는 유사도를 비교할 때 단순히 단어의 출현횟수만을 가지고 문서를 수치데이터(벡터)로 바꾸지 않고 TFIDF라는 수치값을 계산해서 씁니다. 그래서 코사인유사도와TFIDF는 늘 쌍으로 같이 언급이 됩니다. 이건 나중에 따로 설명하겠습니다. (TFIDF에 대한 포스트를 참고하세요)

*위의 3번의 클러스터링에서의 문제*

클러스터링에서의 거리 계산은 모두 연산 자원 문제와 관련이 있습니다. 코사인 유사도 역시 그렇습니다.

유사도를 구하는 목적의 근본적인 목적이 AB와 유사한지 AC가 더 유사한지와 같은 상대적인 비교를 하기 위한 것입니다.

A와 B가 둘만 있다면 둘을 비교해서 둘이 얼마나 유사한지는 사실 알 수 없습니다.  알 필요도 없습니다.

예를들어 세상에 사람이 둘 만 남았는데 두 사람은 비슷하게 생긴 사람일까요? 전혀 다른 사람일까요? 모릅니다.

즉 A와B, C, …등등이 있으면 가장 유사한 것들끼리 묶어보거나 A와 가장 비슷한것을 B, C 와 같은 것 중에서 찾아서 고르는 경우가 대부분이기 때문입니다. 그래서 여러 개의 벡터를 대상으로 각각 서로 서로 쌍을 맺어 유사도를 구해서 가장 유사도가 높은 순으로 정렬해서 가까운 것 1개를 선택한다거나 여러개를 선택해서 여러가지 목적으로 사용하게 됩니다.

클러스터링을 할 때도 마찬가지겠지요 벡터의 개수 즉, 비교할 데이터가 n개고 벡터로 표현할 수 있다면 \frac{n \times (n-1) }{2}번 만큼 연산을 해야 합니다. RDMBS에 100개의 레코드가 있고 컬럼이 여러개 있는데 모두 숫자라면 각 레코드들 간의 유사도를 모두 구하면 \frac{100(100-1)}{2} 만큼 유사도값을 뽑아야 합니다. 에… 계산하면 4950번 입니다.

코사인 유사도를 위한 전제 조건

  • 두 벡터의 원소들은 모두 양수(플러스!)여야 합니다. x, y 직교 좌표축에서 1사분면에 오는 것들입니다. (모눈종이에서 중심을 기준으로 오른쪽 위)
    그래서 원소들이 음수가 되지 않는 문제에만 갖다 씁니다.
  • 벡터의 원소수는 같아야 합니다.
    너무 당연한 것입니다. 비교하는 벡터의 원소 갯수가 일치하지 않으면 각각 빠진 것을 0으로 채워서 동일하게 만들어야 합니다. 벡터의 원소 갯수가 좌표축에서의 축의 갯수이기 때문입니다. (ㅇㅇ?)

코사인 유사도의 특징

1사분면의 두 벡터의 코사인 값은 0 ~ 1 사이의 값입니다. 벡터의 각이 작을 수록 1에 가까워지고 클수록 0에 가까워집니다. 따라서 결과를 재가공(rescaling)하지 않고 바로 쓰기 편합니다. 두 벡터가 정확히 직교이면 값이 0이 됩니다.

삼각함수에 나오는 얘기이기 때문에 기억을 하고 있다면 좋겠습니다만… 기억 안나는 분들이 많으시겠죠?

공식

\text{similarity} = cos(\theta) = {A \cdot B \over |A| |B|} = \frac{ \sum\limits_{i=1}^{n}{A_i \times B_i} }{ \sqrt{\sum\limits_{i=1}^{n}{(A_i)^2}} \times \sqrt{\sum\limits_{i=1}^{n}{(B_i)^2}} }

아주 간단한 공식입니다. 고등학교 수학교과서에도 분명 나옵니다.

졸업한 지 오래된 분들이나 이공계가 전공이 아닌 분들은  배우지 않았거나 기억이 안날 수도 있습니다.

매우 쉽기 때문에 한 번 이해를 하고 나면 볼 필요도 없습니다.  앞에서 말씀드렸지만 아예 설명도 안하는 경우도 많습니다.
이 포스트에서는 가능한 자세히 설명을 적어 보겠습니다.

먼저 공식에서 분자 부분과 분모 부분을 나눠서 설명하면 다음과 같습니다.

분자 부분 – 벡터 내적 (vector inner product, dot product)

코사인 유사도 공식에서의 분자 부분은 벡터의 내적(dot product)을 구하는 것입니다. 영어로는 “닷프러덕”이라고 발음합니다. (유튜브 동영상으로 공부하실 것이면…)

\ll A \cdot B \gg 이 벡터의 내적(dot product) 표기입니다.
벡터의 내적은 계산이 매우 쉽습니다.
두 벡터의 각 원소들을 순서대로 짝맞춰서 곱한 다음에 결과들을 다 더하면 됩니다.
바로 밑에 예제를 풀어두었습니다.

아래와 같은 두 벡터가 있다고 하겠습니다. 차원이 5차원인 2개의 벡터입니다.  요소가 5개이기 때문에 5차원입니다.  (외계인이 산다는 그 5차원이 아닙니다) 값은 현실의 예제가 아닌 제가 임의로 마구 넣은 것입니다.

A = (1,2,3,4,5)
B = (6,7,8,9,10)

  • 각각 짝을 지어 잘 곱합니다. 순서를 맞춰서 잘 해줍니다.
    1 \times 6 = 6
    2 \times 7 = 14
    3 \times 8 = 24
    4 \times 9 = 36
    5 \times 10 = 50
  • 곱한 것을 다 더합니다.
    6 + 14 + 24 + 36 + 50 = 130

위의 과정이 벡터의 내적을 구한 것입니다.
끝~ 입니다. 수고하셨어요.

그런데 여기서 벡터의 내적이 왜 나오는지 궁금할 수 있습니다. 각을 구하는데 왜 저런게 필요하지? 뒤에 설명하겠습니다.

분모 부분 – 두 벡터의 크기를 곱한다

분모 부분은 두 벡터의 크기를 각각 구해서 곱하면 됩니다.

|A|는 A벡터의 크기를 말합니다.
|B|는 B벡터의 크기를 말합니다.

분모는 두벡터의 크기를 구해서 곱하면 되는데요 벡터의 크기(norm 이라고 부르는…)가 기억이 안나실 수 있는데요. 원점에서부터의 거리를 말하는데. 이건 기하학적으로 보면 사실 ‘피타고라스 정리‘에서 직각삼각형의 빗변을 구하는 것을 말합니다.
그런데 2차원까지는 직각삼각형인데 3차원부터는 입체가 되고 4차원부터는 아예 모양을 상상도 할 수 없게 됩니다만 그래도 피타고라스 정리로 구할 수 있다고 수학자들이 증명해 놓았습니다. 믿고 쓰면 됩니다.

벡터의 길이는 피타고라스 정리를 사용하면 구할 수 있고 그걸로 2개의 값을 구해서 서로 곱하면 분모 부분은 완성됩니다.

직각삼각형의 빗변의 길이 구하기를 기억하신다면 좋겠네요. 

C=\sqrt{ A^2 + B^2 }
  • A벡터의 크기를 구합니다. 피타고라스 정리.
\sqrt{ 1^2 + 2^2 + 3^2 + 4^2 + 5^2 } = 7.4161984870957
  • B벡터의 크기를 구합니다. 피타고라스 정리.
\sqrt{6^2 + 7^2 + 8^2 + 9^2 + 10^2} = 18.1659021245849
  • 이제 마무리로 구한 것을 곱합니다
7.4161984870957 \times 18.1659021245849 = 134.7219358530751

숫자값들이 소숫점 뒤로 길게 나와서 복잡해 보이지만 별거 아닙니다. 뭐 계산은 계산기나 컴퓨터가 하는 거니까요.

마무리 계산 – 분자를 분모로 나누기

이제 다 구했으니 분자를 분모로 나눕니다.

\frac{130}{134.7219358530751}=0.9649505

위에 계산된 결과 값이 코사인 유사도 값입니다. 약 0.96이네요.

풀어놓고 보니 별거 아닙니다.
R 코드로 풀어보면 이렇습니다.

R도 되지만 Pyhon이나 다는 것도 당연히 계산이 됩니다.  그리고 위의 코드에도 나와 있지만 특별한 경우가 아니라면 굳이 계산식을 따로 구현할 필요는 없습니다. 함수가 다 제공되고 있습니다.

참고: 여기저기 자료를 더 찾아 보시면  코사인 유사도는코사인 제2법칙에서 유도했다고도 되어 있을 것인데 저는 유도까지는 못해드립니다. 귀찮아서요. 검색해서 찾아보면 아마 누군가 유도해 놓은 것이 있을 것입니다.

공식은 그렇다치고 내적이 왜 필요한데?

200px-Dot_Product.svg

저 위의 삼각형 그림을 다시 가져와서 보면서 설명합니다.

코사인 법칙은 피타고라스 정리에서 출발했기 때문에 코사인값을 구하려면 두 벡터가 만드는 내부의 도형이 직각삼가형이어야 합니다. 그런데 위의 그림을 보시면 A, B와 원점이 만드는 도형이 직각삼각형이 아닌 것을 알 수 있습니다.

직각삼각형이 되는 것은 위의 그림에서는 |A|와 B와 원점입니다. 그래서 |A|의 길이를 알아야 합니다. 이 길이를 알아내는 방법이 벡터의 내적을 이용하는 것입니다.

A와 B의 두 벡터가 있을 때 A와 B의 내적을 구하면 B 곱하기 |A| 또는 A 곱하기 |B|를 구할 수 있습니다.

여기서 |A|는 A를 B의 벡터의 선상(또는 연장선상)으로 직교(직각)이 되게 그대로 내린(정사영한다고 표현합니다) 곳과 원점까지의 거리입니다. |B|는 반대편으로 B를 정사영 한 것입니다.

B 곱하기 |A| = |B| 곱하기 A

어느쪽으로 하던지 두 값은 동일합니다. 왜 동일한지까지 설명하려면 지면이 너무 많이 필요해서 생략하겠습니다.

결국 두 벡터의 내적을 구해서 벡터 하나의 크기로 나누면 |A| 또는 |B|의 길이를 구할 수 있어서 직각삼각형을 만들 수 있습니다. 그러면 비로서 코사인값을 계산할 수 있게 됩니다.

그래서 두 벡터가 유사한지 어떻게 알 수 있는가?

이름이 코사인 유사도이니 이것의 용도가 어떤것이 유사한지 아닌지를 확인하는  것이라는것은 유추할 수 있는데 두 개의 벡터만으로는 서로 유사한지 아닌지를 그냥 알기 어렵습니다.  유사한지 아닌지와 가까운지 먼지 판단하는 기준은 상대적인 것입니다. 물론 절대적인 기준값을 하나 정해놓고 유사하다 아니다를 결정하는데 사용해도 됩니다. 하지만 그 기준값은 직접 결정해야 합니다.

위에서 잠깐 설명했지만 코사인의 특징으로 두 벡터의 각이 호도법으로 0도가 되면 코사인 유사도값은 1이되고 호도법으로 각이 커질수록(90도에 가까워 질수록) 0에 가까워진다는 것입니다.  조금 풀어서 설명하면 코사인유사도가 0 또는 Inf가 되면 전혀 유사하지 않은 직교(orthogonal)가 되고 1이 되면 두 벡터의 원점으로부터의 방향이 완전히 겹치게 됩니다.  그런데 이것만으로는 유사한지 아닌지를 판단하기 어렵습니다. 호도법으로 45도 보다 각이 작으면 유사하다고 해야 할까요?

유사도는 상대적인 개념이기 때문에 벡터 2개로는 두 벡터가 유사한지 아닌지를 알기는 어렵습니다.

그래서 N개의 벡터가 있고 A라는 1개의 벡터가 있을때 A벡터와 가장 가까운 벡터를 N개 중에서 찾을 때 코사인 유사도를 사용해서 코사인 값이 가장 큰 것을 선택해서 사용합니다. 당연히 코사인값은 N번 계산해야 합니다.

A벡터가 상대적으로 가장 가까운 벡터는 어떤 것인가를 구하는데 씁니다.

어째서 두 벡터의 거리를 계산하지 않고 각을 사용하는가?

두 벡터가 가까운지 아닌지를 찾는 방법중에 가장 쉬운 것이 직선거리를 계산하는 유클리디안 거리(Euclidean distance)입니다.  유클리디안 거리의 문제점은 각 축의 수의 크기에 따라 영향을 크게 받는다는 것입니다.  축이 수량값을 나타내는 것이고 각축의 값들이 매우 큰 벡터들가 매우 적은 벡터들이 섞여 있다면 벡터의 성향보다는 양적수치가 비슷한 벡터끼리 가깝게 계산되는 경우가 많습니다.

벡터의 각 축의 값들의 차이가 매우 큰 경우에는 특히 유클리디안 거리는 이상한 결과를 보일 수도 있습니다.

텍스트마이닝에서의 코사인 유사도

코사인 유사도는 텍스트 데이터(텍스트 마이닝)에 사용하는 경우가 많습니다.  물론 다른 곳에도 많이 쓰입니다만 자료를 찾아보면 눈에 쉽게 띄는 쪽은 텍스트 마이닝과 관련된 것 입니다. 텍스트에서 추출한 텀(term, 단어, 색인어)들의 빈도의 분포가 지수 스케일이기 때문에 벡터의 사잇각을 두고 비슷한 방향인지 아닌지를 보는 방법이고 이게 비교적 합리적인 방법이기 때문입니다.

그리고 검색엔진에서 질의어로 본문을 찾아서 유사한 것을 찾는데 질의어와 본문이 가지고 있는 단어들의 빈도수 같은 것의 양적차이가 매우 크기 때문에 코사인 유사도가 유리합니다.

텍스트마이닝에서 코사인 유사도의 주의점

텍스트 데이터는 분량(데이터 사이즈)이 많기 때문에 코사인유사도 값을 구하려고 해도 현실에서는 컴퓨터 연산이 많이 소모되어서 하지 못하는 경우도 있습니다. 이런 작업을 하려면 사실은 대부분의 경우 분산 프로세싱을 수행해서 구해야 합니다.  크기가 적당하다면 RDBMS를 사용하고 아니면 Hadoop이나 Spark같은 분산 컴퓨팅 환경에서 작업해야 할 수도 있습니다.

Excel이나 R, Python으로는 계산하기에 너무 무거울 정도로 문서가 많고 그 상황에서도 코사인유사도 계산을 해야 한다면 위의 과정을 이해하는 것이 문제해결을 위해서 좋습니다.

요즘은 빅데이터 플랫폼들이 좋아서 위의 간단한 계산 방식만 이용하면 빅데이터 플랫폼으로 어렵지 않게 대량의 벡터들이나 텍스트데이터의 유사도를 구할 수 있습니다.

텍스트 데이터를 가지고 코사인 유사도(Cosine Similarity)를 구해서 문서간의 유사도를 구하는 것은 다음 포스트에 해 보겠습니다.

TFIDF – Term Frequency Inverse Document Frequency