본문 바로가기

데이터와 함께 탱고를/머신러닝

코사인 vs 유클리디안 유사도, 케이스로 이해하기

벡터 간 유사도 측정에는 여러가지 방법이 있지만,
여기서는 코사인 유사도와 유클리디안 유사도만 다룬다.
기본 개념은 구글링 치면 훌륭한 글들이 많으니, 거기서 참고하면 된다.
여기서는 직접 두 벡터를 가지고 요리조리 굴려보며, '직관적으로' 어떻게 다른지 느껴보고자 한다.

먼저 두 벡터가 완전히 동일한 경우를 보자.

a = np.array([[1, 0, 0]])
b = np.array([[1, 0, 0]])

print(cosine_similarity(a, b))
print(euclidean_similarity(a, b))

# output
[[1.]]
[[1.]]

두 유사도 값 모두 1이 나온다.

그 값만 조금 다른 경우를 보자.

a = np.array([[1, 0, 0]])
b = np.array([[2, 0, 0]])

print(cosine_similarity(a, b))
print(euclidean_similarity(a, b))

# output
[[1.]]
[[0.5]]

코사인 유사도는 변하지 않았지만, 유클리디안 유사도는 변했다.

이번에는 값은 같되, 축이 다른 두 벡터를 보자.

a = np.array([[1, 0, 0]])
b = np.array([[0, 1, 0]])

print(cosine_similarity(a, b))
print(euclidean_similarity(a, b))

# output
[[0.]]
[[0.41421356]]

코사인 유사도는 0으로, 아예 다른 벡터라고 말하지만 유클리디언 유사도는 어느정도 값을 나타낸다.

다음과 같이 벡터 내 0이 아닌 값을 좀 더 멀리보내 변형을 줘도 결과는 같다.

a = np.array([[1, 0, 0]])
b = np.array([[0, 0, 1]])

print(cosine_similarity(a, b))
print(euclidean_similarity(a, b))

# output
[[0.]]
[[0.41421356]]

이번에는 다음과 같이 벡터를 구성해보자. 축은 같되, 크기가 좀 다르다.

a = np.array([[4, 1, 0]])
b = np.array([[2, 1, 0]])

print(cosine_similarity(a, b))
print(euclidean_similarity(a, b))

# output
[[0.97618706]]
[[0.33333333]]

코사인 유사도에서는 두 벡터가 매우 비슷함을 드러내고 있지만, 유클리디안 유사도에서는 전혀 그렇지 않다.

다음 예시에서 이런 면이 가장 극명하게 드러난다.

a = np.array([[1, 0.25, 0]])
b = np.array([[1, 0.5, 0]])

print(cosine_similarity(a, b))
print(euclidean_similarity(a, b))

# output
[[0.97618706]]
[[0.8]]

a, b 는 직전 예시와 크기만 다를 뿐, 사실 동일하다.
그래서 코사인 유사도는 직전 예시와 같은 값을 나타내지만,
유클리디언 유사도는 직전 예시보다 훨씬 올라갔다.

코사인 유사도 공식을 보면, 두 벡터의 곱을 할 때 두 벡터는 각자의 벡터의 크기만큼 나누는 뒤 곱한다.
즉, 벡터 자체적으로 일종의 스케일링을 하는 것이다.
따라서 코사인 유사도에서는 서로 다른 스케일을 가지고있는 벡터더라도, 동일한 스케일로 만든 뒤 계산을 한다.
즉 나름 합리적인 유사도라고 할 수 있다.

이에 반면, 유클리디안 벡터는 이보다 훨씬 naive 한 느낌이다.
벡터 내 원소의 값 차이를 기반으로 유사도를 구한다.
이런게 극명히 문제가 되는 경우는, 다음과 같은 경우다.

a = (1, 2, 3000000, 4, 5)
b = (2, 3, 4000000, 5, 6)
c = (3, 4, 5000000, 6, 7)

출처 : http://euriion.com/?p=412115

3번째 원소의 스케일이 너무커서, 다른 원소의 차이의 영향이 매우 미미해진다.

그렇다면 반면, 벡터끼리 스케일이 완전히 같은 경우는 어떤 유사도가 더 의미있을까?
예를 들어, 다음과 같이 모든 벡터가 0~1 사이의 값을 갖고있다면..?

a = (0.1, 0.5, 0  , 0.7)
b = (0.2, 0.3, 0.1, 0  )
c = (0.3, 0  , 0  , 0.5)

이 때는, 유클리디안도 코사인도 모두 의미가 있어보인다.
만약 내가, 양적인 차이를 알고 싶다면 유클리디안 유사도를,
질적인 ? 근본적인? (basis) 차이를 코사인 유사도를 써야하는 듯 하다.

사실은 나도 확실치 않아서 이런 경우는 실험적으로 두 개 모두 써보고 있다.

아무튼 나만을 위한 정리 끝.