Cosine Similarity – 코사인 유사도

위키피디아에 설명이 잘 되어 있습니다.
그래서 위키피디아의 내용을 신뢰하고 좋아하신다면 당연히 위키피디아의 내용을 먼저 참조하면 됩니다.  (이미 보셨을지도 모르겠습니다만)

한국어 위키피디아 보다는 영문 위키피디아가 정리가 잘 되어 있습니다.  참조하실 것이면 영문위키피디아를 보는 것이 더 낫다고 생각합니다.

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

200px-Dot_Product.svg

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

이때 유사도를 구할 때 두 벡터 사이의 각을 코사인(Cosine)으로 구해서 유사도로 사용하기 때문에 코사인 유사도(Cosine Similarity)라고 부릅니다. 그게 전부입니다.  (기하학적으로 설명하자면요)

유사도를 구하는 방법은 여러개가 있습니다. 코사인 유사도는 그 중 하나입니다.

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

위의 그림에서 두 벡터는 2차원입니다. 축이 2개있는 평면이니까요.  하지만 벡터는 2차원 이상의 고차 벡터가 더 많습니다. 기하적인 차원과는 조금 다르기도 합니다.

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차원 벡터는 시각적으로 표현할 수 없습니다. 하지만 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에 가까워집니다. 따라서 결과를 재가공하지 않고 바로 쓰기 편합니다. 두 벡터가 정확히 직교이면 값이 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 코드로 풀어보면 이렇습니다.

 

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

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

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

추가로

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

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

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

TFIDF – Term Frequency Inverse Document Frequency

빅데이터와 텍스트마이닝

빅데이터와 테스트 마이닝에 대해서 조금 적으려고 합니다.

빅데이터(Big data)

빅데이터(Big data)는 이제는 설명을 안해도 될 만큼 자료가 많습니다.
구글링을 해서 찾아보시면 되겠지만 너무 많아서 오히려 정리가 안되서 맥락을 이해하기가 어려울 수도 있습니다.

빅데이터는 간단하게 말하면 많은 데이터, 다양한 데이터를 저장, 가공, 처리, 분석하는 것을 통칭해서 말하는 것입니다. 어차피 명확하게 정의하기 어렵고 원래 정의를 만들고 시작한 것도 아닙니다.

사실 이미 빅데이터 리딩그룹쪽에서는 데이터와 관련된 IT기술이나 분석기법은 그 경계나 정의를 명확하게 정하지 않은지가 오래 되었습니다.

텍스트 마이닝 (Text Mining)

텍스트 마이닝은 사람이 써놓은 글을 분석해서 뭔가 쓸만한 것을 뽑는 것입니다.

텍스트 데이터는 특성상 많이 모아야 뭔가 쓸만한 것이 나옵니다. 텍스트 마이닝이 빅데이터에서 언급되고 마치 전부인것 처럼 얘기되기도 하는 이유는 원래 빅데이터의 출발이 IR(Information Retrieval)이 전문인 구글, 야후, 페이스북, 아마존, 넷플릭스등의 온라인 회사에서 시작되었기 때문입니다.  즉 빅데이터 관련 기술을 텍스트 처리에 많이 사용했기 때문입니다.

검색 포털이나 온라인 리테일 회사를 상상하시면 됩니다. 구글, 아마존이 대표적입니다.

이미 아시겠지만 현존하는 텍스트 마이닝의 최강자는 구글입니다. 그리고 그 외의 여러 회사들이 있습니다.

이 회사들의 공통점은 다음과 같습니다.

  1. 온라인 회사이고 많은 접속자가 만들어 낸 로그를 쌓아서 보유하고 있는 데이터가 매우 많다
  2. 대용량 정보처리기술이 회사의 핵심기술이다
  3. 사용자들이 웹사이트에서 행동하는 것을 로그에 쌓아놓고 그것을 다시 가공해서 회사의 서비스를 개선하거나 다른 부가가치를 만들어 낸다

빅데이터와 텍스트마이닝이 혼동되는 이유 중 또 하나는 텍스트데이터는 처리하는데 컴퓨팅 자원이 많이 소모된다는 점도 있습니다.

어찌되었든 텍스트 마이닝을 잘 하려면 필수는 아니지만 빅데이터 기반 기술이 있는 것이 매우 유리하며 그런 경험이 있다면 그렇게 될 수 밖에 없다고 보는 것이 업계 기술자들의 정론입니다.

그렇다고해서 빅데이터를 텍스트 마이닝에만 쓴다는 얘기는 아닙니다. 다시 텍스트 마이닝으로 돌아오면 텍스트 마이닝은 텍스트 데이터를 분석해서 의미, 의도, 경향등을 보는 것을 기본으로 하고 그런 결과물을 다른 데이터와 연동해서 분석하거나 결합해서 부가정보로 쓰게 됩니다. 그 이상을 하려면 텍스트 마이닝 결과물 자체가 비즈니스 모델이 되거나 회사의 이윤을 창출하는 뭔가를 만들어 주어야 하는데 그런것이 많지 않습니다.

텍스트 마이닝이 그 자체로 비즈니스 모델이 되는 것은 기계 번역이나 문서 자동 요약 등과 같은 것이 있습니다.

텍스트 마이닝의 문제점

텍스트 마이닝의 문제점은 상당히 자연어(사람이 쓰는 말, 한국어, 일본어, 독일어, 영어, …)에 영향을 많이 받으며 분석결과물 자체를 그대로 비즈니스 모델에 적용해서 뭔가를 만들어내서 성과를 보기 어렵다는데 있습니다. 자연어처리쪽 분야에 있어서 문제가 있는 분야가 한글 및 한국어의 경우 광학문자판독(OCR, Optical Character Recognition), 음성인식(Speech Recognition), 그리고 감성분석 (Sentimental Analysis)등이 있습니다. 기술적으로 문제라기 보다는 언어를 다루는 문제가 결과물을 보고 품질을 사람들이 쉽게 판단하기 때문입니다.

텍스트 마이닝이 어려운 이유

텍스트 마이닝의 전부가 워크 클라우드가 아니며 데이터를 수집해서 텍스트 마이닝 툴을 사용해서 마우스 클릭을 하면 분석결과가 나오는 것이 아닙니다. 영어권 경우에는 기술적인 진척이 많고 영어의 특성이 분석이 더 쉽다는 것이 없지 않아 잘 되는 것도 있지만 한글 및 한국어에서는 아직은 어렵습니다. 특히 텍스트 마이닝은 자연어처리 도구에 의존성을 매우 큰데, 자연어처리 도구가 그냥 사서 쓰는 소프트웨어가 아니라 사람의 정성스런 손길이 지속적으로 필요한 애물단지입니다. 자체로도 관리가 필요하며 관리가 안되면 쓸모가 없어지는 경우가 많으데다가 관리가 안된 자연어처리 도구를 이용해서 만든 2차 파생물도 함께 엉망이 됩니다.

때문에 사내(in-house)에서 지속적으로 투자하거나 하지 않으면 결과를 보기 어렵고, 당연히 단기 프로젝트에 의한 좋은 결과물은 나오기 어렵습니다. 참고로 자연어 처리 도구는 형태소 분석기, 구문 분석기등과 같은 자연어를 처리하는데 필요한 소프트웨어 라이브러리들입니다. 이것들도 자연어의 특성을 많이 타는 것으로 각 언어별로 다 품질이 다르고 기분석 사전이나 후처리 사전등을 따로 관리해야하는 복잡한 문제가 있습니다.

텍스트 마이닝과 워드 클라우드(Word Cloud)

TV에서 자주 볼 수 있는 화면이 단어들이 둥둥 떠 있고 단어끼리 선을 연결한 시각화 화면이 많은 것입니다. 워드 클라우드라는 시각화 방법입니다.

사실상 텍스트 마이닝의 결과물의 시각화는 워드 클라우드나 워드 클라우드를 변형한 시각화 기법외에는 아직 없습니다

경험이 없는 분들은 어렵게 생각하실지도 모르겠지만 사실 워드 클라우드는 구현하기가 매우 쉽흡니다. 심지어 그냥 오픈 소스 몇개를 붙여서 돌리면 그럴 듯한 것을 만들어서 보여줄 수 있습니다.
문제는 이런것들 돌려서 흥미 위주의 어필 포인트는 되겠지만 결과물이 실제로 도움이 되는 것이 많지 않다는 것이고 그것 때문에 대부분의 일반 기업에서는 빅데이터를 텍스트 마이닝이라고 생각하고 프로젝트를 진행한 뒤에 결과물이 도움이 안되니 빅데이터가 별거 아니고 해봤는데 아니더라고 말하게 된다는 것입니다.

가장 흔히 볼 수 있는 반응입니다

이것은 잘못 접한 정보와 유도된 상황 때문에 발생하는 착각입니다. 빅데이터와 텍스트 마이닝을 구분하지 못하며 제대로 이해하지 못하기 때문입니다.  경험을 해보지 않으면 제대로 구분하기 어려운 것도 사실입니다만 공부가 부족하기 그것을 모른다고 해서 틀린 것을 말하고 그것이 마치 정설인듯 말하는 것은 정당하지 않습니다. 텍스트 마이닝은 쉽지 않습니다. 그리고 텍스트마이닝이 빅데이터와 동치관계는 아닙니다.