[ML] 유사도 검정

2021. 4. 6. 02:47ML&DL

문서의 유사도를 검정하는 방법에 대해 알아보겠습니다.

 

순서

1. 자카드 유사도

2. 코사인 유사도

3. 코사인 유사도 vs. 유클리디안 유사도

 

1. 자카드 유사도

 

자카드 유사도는 두 문서에서 공통되는 단어가 많을수록 다른 단어가 적을수록 비슷한 문서라고 판단하는 가장 간단한 유사도 기법입니다. 식으로 나타내면 공통 단어 개수/전체 단어 개수로 아래와 같습니다. 

 

 

 

 

자카드 유사도를 구하는 함수는 아래와 같습니다.

 

 

 

자카드 유사도는 원소의 개수에 따라 0~1 사이의 값을 가지고 1에 가까울수록 유사도가 높습니다.

 

 

2. 코사인 유사도

 

코사인 유사도는 순서 상관없이 단어를 벡터로 바꾼 후에 벡터 방향을 이용하여 유사도를 계산하는 방법입니다. 벡터의 방향이 같으면 코사인 유사도는 1, 직각이면 0, 다른 방향이면 -1입니다. 벡터의 크기에는 영향을 받지 않고 방향에만 영향을 받습니다. 예를 들어 바나나를 조금 좋아한다, 바나나를 많이 좋아한다, 사과를 조금 좋아한다.라는 문장이 있을 때 바나나를 조금 좋아하든, 많이 좋아하든 방향으로만 유사도를 구하기 때문에 사과를 조금 좋아하는 사람보다 바나나를 좋아하는 것의 유사도가 더 높다고 판단하는 것입니다. 

 

 

 

그렇다면 문장들이 같은 방향인지 어떻게 계산할까요? 먼저, 단어들을 벡터화시키고 단어를 축으로 하는 특성 공간에 문서에 해당하는 각 좌표를 찍는 것입니다. 만약 바나나를 많이 좋아해, 사과를 많이 좋아해라는 문장이 있으면 아래와 같이 좌표를 찍어서 벡터가 방향을 이용해 유사도를 구하는 것입니다. 

 

 

 

단어를 벡터로 바뀌는 것을 벡터화라고 하고 단어를 벡터로 바꾸는 대표적인 방법은 각 단어가 문서에서 몇 번 등장했는가를 벡터화하는 CountVectorizer, 중요하지 않은 단어에 가중치를 조금 주고 중요한 단어에 가중치를 많이 주는 TF-IDF Vectorizer가 있습니다.

 

 

CountVectorizer는 단어의 빈도를 계산하여 아래와 같은 문서 단어 행렬을 만들어줍니다. 문서 단어 행렬은 각 단어들의 빈도를 행렬로 표현한 것입니다. 아래처럼 나타낸 것을 문서 단어 행렬이라고 합니다. 

 

  나는 바나나를 사과를 좋아해 많이
나는 바나나를 많이 많이 좋아해 1 1 0 1 2
나는 사과를 좋아해 1 0 1 1 0

 

문서 단어 행렬은 대부분의 값이 0인 희소 벡터 또는 희소 행렬이라고 부릅니다. 희소 벡터 또는 희소 행렬은 많은 양의 저장 공간과 계산을 위한 리소스를 필요로 하기 때문에 방대한 데이터에서 사용할 때는 집합의 크기를 줄이는 것이 좋습니다. (불용어 제거, 구두점 제거와 같은 전처리 필요)

 

CountVectorizer는 단순 빈도수에 기반하기 때문에 중요하지 않은 '저', '이'와 같은 단어들로 인해 유사하다고 판단할 수도 있습니다. 이를 방지하기 위한 방법으로 TF-IDF Vectorizer기법이 있습니다. TF-IDF는 모든 문서에서 자주 등장하는 단어는 중요도가 낮고 특정 문서에서만 자주 등장하는 단어는 중요도가 높다고 판단하는 기법입니다. TF-IDF 값이 낮으면 중요도가 낮다,  값이 높으면 중요도가 높다고 판단합니다. 그럼 TF, IDF 나눠서 살펴보겠습니다.

 

TF는 Term Frequency의 줄임말로 특정 단어가 문서 내 등장한 단어의 빈도입니다. IDF는 Inverse Document Frequency의 약자로 특정 단어가 전체 문서에 등장한 수의 역수입니다. 

 

아래와 같은 문서 단어 행렬이 있을 때 '나는 바나나를 많이 많이 좋아해' 에서 '나는'이 출현한 빈도는 tf(나는 , 나는 바나나를 많이 많이 좋아해) = 1입니다. 그리고 전체 문서에서 '나는'이 등장한 빈도는 df(나는) = 2 입니다. 

  나는 바나나를 사과를 좋아해 많이
나는 바나나를 많이 많이 좋아해 1 1 0 1 2
나는 사과를 좋아해 1 0 1 1 0

이에 역수를 취하여 출현 빈도가 작은 단어에 높은 가중치를 주도록 합니다. 그리고  idf는 분모가 0이 되는 것을 막기 위해 1을 더하고 log를 취하여 대량의 문서에서 단어셋을 만들어도 한 번만 출현하여 IDF 값이 너무 커지는 경우를 막습니다. 

 

TF-IDF 수식

 

sklearn을 이용하면 쉽게 CountVectorizer와 TF-IDF Vectorizer를 사용할 수 있습니다. sklearn에서 제공하는 TF-IDF Vectorizer모듈의 수식은 위 수식과 달리 idf가 0이 되는 것을 막기 위해 idf에도 1을 더해줍니다. 그리고 마지막에 모든 문서 벡터의 길이가 1이 되도록 정규화하여 각 문서가 방향만 가지게 만듭니다. 

 

CountVectorizer

 

fit_transform을 적용하면 메모리 낭비가 적어지도록 하기 위해 희소 행렬을 반환합니다. toarray()를 이용하여 넘파이 배열로 나타내어 확인하였습니다. 행은 각각의 문서(문장), 열은 각 단어를 의미합니다.  

 

TF-IDF Vectorizer

 

 

이제 문서를 벡터로 표현하는 방법에 대해 알았기 때문에 코사인 유사도를 구할 수 있습니다. 문서 단어 행렬을 이제 그래프 상에 나타내어 위에서 보았던 수식(x벡터와 y벡터의 내적을 구하고 x벡터의 길이와  y벡터의 길이로 나누어 x벡터와 y벡터가 이루는 각의 코사인 값을 구하는 수식)에 적용하여 값을 계산합니다. sklearn에서 linear_kernel 함수 또는 cosine_similarity함수에 문서 단어 행렬을 입력값으로 넣어주면 유사도를 계산해줍니다.

 

 

 

 

3. 코사인 유사도 vs. 유클리디안 유사도

 

벡터 간 거리를 구하는 방법은 각도 기반으로 계산하는 코사인 유사도 외에도 거리 기반으로 추천하는 유클리디안 방법이 있습니다. 유클리디안 유사도는 직선거리를 계산하는 유사도 기법이기 때문에 0에 가까울수록 유사하다고 판단합니다. 

 

 

유클리디안

 

유클리디안 거리는 벡터의 크기에 민감하므로 단어의 수가 많아지면 벡터의 길이가 길어지고 해당 문서와 다른 문서의 거리도 멀어집니다. 그래서 보통 벡터 길이가 다를 때 따로 정규화해주지 않으려면 단어 간의 조합이 비슷할수록 유사하다고 판단하는 cosine을 사용할 수 있습니다. 

 

아래 그림을 참고하면 거리 기반 추천 방식인 유클리디안 유사도와각도 기반 추천 방식인 cosine 유사도가 유사하다고 생각하는 것들이 다르다는 것이 보입니다.

 

 

참고

[1] 유사도 처리법 - 자카드 유사도(Jaccard Similarity), 코사인 유사도(Cosine Similarity), 유클리디안 유사도(Euclidean Similarity)

[2] 코사인 유사도의 의미

728x90