본문 바로가기
자연어 처리

[딥러닝을 이용한 자연어 처리 입문] 벡터의 유사도

by 나연하야 2023. 4. 6.

여러 개의 문서 중에 주제가 유사한 문서끼리 분류하는 작업이 필요한 경우가 있을 수 있으며, 이와 같은 작업의 성능은 각 문서의 단어들을 어떤 방법(DTM, Word2Vec)으로 수치화하여 표현했는지와 문서 간의 단어들의 차이를 어떤 방법(유클리드 거리, 코사인 유사도 등)으로 계산했는지에 따라 달라짐

오늘은 단어들의 유사도를 측정하는 방법에 대해서 학습할 예정임

 

  • 코사인 유사도

코사인 유사도는 두 벡터 간의 코사인 각도를 이용하여 구함

두 벡터의 방향이 완전히 동일한 경우에는 1, 90도의 각을 이루면 0, 180도로 반대의 방향을 가지면 -1 값을 가짐

즉, 코사인 유사도는 -1이상 1이하의 값을 가지며 1에 가까울수록 유사도가 높다고 판단할 수 있음

 

코사인 유사도를 구하는 식은 아래와 같음

3개 문서의 유사도를 구하는 과정은 다음과 같음

문서1: 저는 사과 좋아요

문서2: 저는 바나나 좋아요

문서3: 저는 바나나 좋아요 저는 바나나 좋아요

위 3문서에 대해 문서-단어 행렬(DTM)을 만들면 아래와 같음

  바나나 사과 저는 좋아요
문서1 0 1 1 1
문서 1 0 1 1
문서3 2 0 2 2
import numpy as np
from numpy import dot
from numpy.linalg import norm

def cos_sim(A, B):
  return dot(A, B)/(norm(A)*norm(B))

doc1=np.array([0,1,1,1])
doc2=np.array([1,0,1,1])
doc3=np.array([2,0,2,2])

print('문서1과 문서2의 유사도:', cos_sim(doc1, doc2))
print('문서1과 문서3의 유사도:', cos_sim(doc1, doc3))
print('문서2과 문서3의 유사도:', cos_sim(doc2, doc3))
문서1과 문서2의 유사도: 0.6666666666666667
문서1과 문서3의 유사도: 0.6666666666666667
문서2과 문서3의 유사도: 1.0000000000000002

위의 3개의 문서의 유사도를 구한 결과를 보면 문서1과 2의 코사인 유사도와 문서1과 3의 코사인 유사도가 같고, 문서2와 문서3의 코사인 유사도는 1이라는 점임

문서3은 문서2에서 모든 단어의 빈도 수가 1씩 증가한 것으로 이와 같은 경우는 코사인 유사도가 1로 산출됨

즉, 두개의 문서가 동일한 주제이지만 문서의 길이만 다를 경우 코사인 유사도는 큼

 

  • 유클리드 거리

유클리드 거리는 다차원 공간에서 두 개의 점 p와 q가 각각 p=(p_1, p_2, ..., p_n), q=(q_1, q_2, ..., q_n)의 좌표를 가질 때 아래와 같이 구할 수 있음

예를 들어, 2차원 좌표 평면에 있는 점이라면 우리가 알고있는 두 점 사이의 거리가 유클리드 거리임

유클리드 거리를 이용해 문서1, 2, 3 중에서 문서Q와 가장 가까운 문서를 구하는 과정은 아래와 같음

  바나나 사과 저는 좋아요
문서1 2 3 0 1
문서2 1 2 3 1
문서3 2 1 2 2
문서Q 1 1 0 1
import numpy as np

def dist(x,y):
  return np.sqrt(np.sum((x-y)**2))

doc1=np.array([2,3,0,1])
doc2=np.array([1,2,3,1])
doc3=np.array([2,1,2,2])
docQ=np.array([1,1,0,1])

print('문서1과 문서Q의 유사도:', dist(doc1, docQ))
print('문서2과 문서Q의 유사도:', dist(doc2, docQ))
print('문서3과 문서Q의 유사도:', dist(doc3, docQ))
문서1과 문서Q의 유사도: 2.23606797749979
문서2과 문서Q의 유사도: 3.1622776601683795
문서3과 문서Q의 유사도: 2.449489742783178

 

  • 자카드 유사도

자카드 유사도는 두개 집합의 합집합에서 교집합의 비율을 구한 것임

자카드 유사도의 경우 0에서 1 사이의 값을 가지며, 두 집합이 동일하면 1의 값, 공통 원소가 없다면 0의 값을 가짐

두 문장의 자카드 유사도를 구하는 과정은 아래와 같음

doc1 = "apple banana everyone like likey watch card holder"
doc2 = "apple banana coupon passport love you"

tokenized_doc1=doc1.split()
tokenized_doc2=doc2.split()

print('문서1: ', tokenized_doc1)
print('문서2: ', tokenized_doc2)

union=set(tokenized_doc1).union(set(tokenized_doc2))
intersection=set(tokenized_doc1).intersection(set(tokenized_doc2))

print('자카드 유사도:', len(intersection)/len(union))
문서1:  ['apple', 'banana', 'everyone', 'like', 'likey', 'watch', 'card', 'holder']
문서2:  ['apple', 'banana', 'coupon', 'passport', 'love', 'you']
자카드 유사도: 0.16666666666666666

출처: 유원준/안상준, 딥러닝을 이용한 자연어 처리 입문-1권, p158-p168.