지난 번 글에서 언급했듯이 군집 분석을 하려면 먼저 개체간의 비슷한 정도를 어떻게 정량화할지 정해야 합니다. 이런 비슷한 정도를 '유사도' 혹은 '거리'라고 부릅니다. 이 글에서는 '유사도'라는 말과 '거리'라는 말을 혼용해서 사용할 텐데, 기본적인 개념은 비슷하며 다만 유사도는 값이 클수록 비슷한 것을 의미하고 거리는 반대로 값이 작을수록 비슷하다는 것을 의미합니다.
유사도를 측정하기 위해선 두 가지를 결정해야 합니다. 하나는 어떤 값을 이용해 유사도를 측정할 것이지이고, 또 하나는 어떤 방법을 이용해서 정량화를 할 것인지입니다. 전자는 데이터의 특질(feature)를 의미하며, 후자는 유사도 알고리즘을 의미합니다.
예를 들어, 고객 세분화를 위해 군집 분석을 한다고 가정해 보죠. 이 때 군집 분석을 위해 사용하는 고객의 인구 통계 정보(성별, 연령, 사는 지역 등)와 구매 정보(구매한 총 금액, 구매한 물품의 종류, 구매한 물품 개수 등)가 데이터의 특질에 해당합니다. 어떤 특질을 사용할 것인가는 군집 분석의 목적에 따라 다릅니다. 앞서 아트박스 사장님의 예를 다시 들자면, 만약 군집 분석의 목적이 비슷한 구매 성향을 가진 고객끼리 묶어서 맞춤형 할인 쿠폰을 발급하는 것이라면, 실상 인구 통계 정보보다는 구매 정보를 이용하는 것이 더 좋을 수 있습니다. 혹은 인구 통계 정보를 이용하더라도 단순하게 연령대를 나누기 보다는 좀 더 구매 성향에 맞게 범주를 나누는 것이 필요하겠죠. 다시 말해, 10대, 20대, 30대, ... 이런 식으로 나누기 보다는 초등학생, 중학생, 고등학생, 대학생, 사회 초년생, ... 이런 식으로요.
참고로 특질 선택이 잘못되면 이후 과정을 아무리 잘하더라도 좋은 결과가 나오지 않습니다. 따라서 전체 과정에서 이 특질 선택 단계가 가장 중요하다고 해도 과언이 아닙니다. 그러나 안타깝게도 군집 분석에서 특질 선택을 어떻게 하면 잘할까에 대해선 딱히 알려진 좋은 방법은 없습니다. 그래서 보통 특질을 선택할 때는 해당 도메인의 전문가와 함께 여러 가지 탐사 분석 과정을 거치는 것이 필요합니다.
이렇게 유사도를 측정할 특질들이 선택되고 나면, 이에 맞는 적절한 유사도 측정 방법을 정해야 합니다. 유사도를 측정하는 방법은 매우 다양하지만, 보통 사용하는 특질 데이터의 속성에 따라 거기에 맞는 유사도 측정 방식이 몇 가지 후보로 정해집니다. 여기서는 각 사례별로 몇 가지를 소개하겠습니다.
가장 널리 사용되는 방법이 좌표 상의 거리를 구하는 것입니다. 말그대로 각각의 데이터(예를 들면 고객)를 좌표상의 점으로 표현하고 점들 사이의 거리를 구하는 것을 말합니다.
위 그림에서는 보기 편하려고 '플레이시간'과 '경험치획득량' 이라는 두 개의 특질만을 사용한 예시를 들었지만 특질 개수는 여러 개가 되더라도 상관없습니다. 3개 이상의 특질이 있더라도 위에 있는 식과 동일하게 동일한 특질끼리 값을 뺀 후 제곱을 해서 더해 나가면 됩니다. 예를 들어 게임 유저 A, B의 거리를 구할 때 '플레이시간', '경험치획득량', '아이템구매금액', '아이템구매횟수' 라는 네 개의 정보를 이용한다면 둘 간의 거리는 아래와 같이 계산하면 됩니다.
보통 군집 분석 대상의 특질 정보들이 숫자형 데이터라면 이렇게 좌표 상의 거리 구하는 방법을 이용합니다. 그런데 만약 일부 데이터가 숫자형 데이터가 아니라 범주형(category) 데이터인 경우엔 어떻게 할까요? 예를 들어 게임 유저 정보에 '성별'이나 '직업' 같은 데이터를 추가한다면 이 때는 어떻게 거리를 구해야 할까요?
일반적으로 범주형 데이터를 숫자형 데이터로 만들기 위해선 '더미 코딩 (dummy coding)' 이라는 방법을 이용합니다. 더미 코딩이란, 범주형 변수를 여러 개의 숫자형 변수 - 이것을 더미 변수 (dummy variable) 이라고 함 - 로 변환하는 방법을 말합니다. 보통 범주형 변수에 들어가는 '값의 종류 개수 - 1개' 만큼의 더미 변수를 만든 후 각 개체의 범주형 값에 해당하는 더미 변수는 1, 나머지는 0을 채워넣는 방식을 말합니다. 예를 들어 아래와 같이 3개의 범주를 갖는 어떤 변수가 있다면 해당 변수 대신 2개의 더미 변수를 추가하여 아래와 같이 변환하는 것이죠.
한 가지 눈여겨 볼만한 점은 아래 예시와 같이 '유형3'에 대해서는 따로 더미 변수를 만들지 않고 '유형1' 변수와 '유형2' 변수를 모두 0으로 처리하여 '유형3'인 경우를 표현한다는 점입니다. 이렇게 하는 이유는 1) 변수의 개수를 최대한 줄일 수 있고 2) 회귀 분석에서는 모든 변수가 0인 상황을 정의하는 것이 모델을 해석할 때 유리하기 때문입니다.
그러나 군집 분석을 할 때는 이렇게 하면 안됩니다. 군집 분석에서 더미 코딩을 할 때는 아래 그림과 같이 모든 범주형 종류에 대해서 더미 변수를 추가해야 합니다.
왜냐하면, 군집 분석에서 개체 간의 거리를 구할 때 유형3에 대한 더미 변수를 따로 만들지 않으면 개체 간의 거리가 불균등하게 구해지기 때문입니다. 가령, 첫번째 방식처럼 유형3 변수를 따로 두지 않고 더미 코딩을 하게 되면 유형1과 유형2 사이의 거리와 유형3과 나머지 개체 간의 거리가 서로 다릅니다. 반면, 유형3 변수를 추가하면 모든 경우에 거리가 동일해지죠. 다시 말해 첫번째 방식으로 더미 코딩을 하고 군집 분석을 하면 유형1과 유형2 의 개체들이 유형3에 비해 덜 유사한 것으로 측정되는 문제가 발생합니다.
정리하자면, 범주형 변수를 숫자형 변수로 만들기 위해선 더미 코딩이라는 방법을 사용하는데, 회귀 분석에서는 범주형 값 종류수 - 1개 만큼의 더미 변수를 만들어 변환하지만, 군집 분석에서는 범주형 값 종류수 만큼의 더미 변수를 모두 만들어서 변환해야 합니다.
지금까지 설명한 좌표 상의 거리를 구하는 방법을 '유클리드 거리 (Euclidian distance)' 라고 부릅니다. 그런데 이 외에도 좌표상의 거리를 구하는 방법은 여러 가지가 있습니다. 유클리드 거리 말고 다른 유명한 거리 구하는 방법으로는 다음과 같은 것들이 있습니다.
맨하탄 거리 (Manhattan distance) - 유클리드 거리는 두 점 사이의 최단 거리를 대각선으로 가로 질러서 구하는 방법인 반면, 맨하탄 거리는 마치 격자형 도로로만 이뤄진 도시에서 두 장소를 이동하듯이 거리를 구하는 방법입니다. 항상 그런 것은 아니지만 개체의 차원이 큰 경우 군집 분석 시 유클리드 거리보다 맨하탄 거리를 이용하는 것이 더 좋다고 알려져 있습니다. (참고논문: https://bib.dbvis.de/uploadedFiles/155.pdf)
마할라노비스 거리 (Mahalanobis distance) - 만약 아래 그림과 같은 데이터가 있을 때 그냥 유클리드 거리를 구하면 A는 C에 비해 B와 거리가 훨씬 더 작게 측정될 것입니다. 그러나 전체 데이터의 분포를 살펴 보면 x축과 y축은 서로 양의 상관이 존재하며 이 때문에 A와 C는 B보다 좀 더 데이터가 밀집된 방향에 위치해 있습니다. 따라서 이렇게 전반적인 데이터의 분포나 분산을 생각해 보면 단순히 B를 C보다 더 가깝다고 판단하는 것은 부적절할 수 있습니다. 다시 말해, 전반적으로 X축과 Y축 변수간에 양의 상관이 있는 상태에서는 B와 같이 전반적인 상관 관계에 역행하는 데이터는 드물게 나타나기 때문에 이런 데이터와 일반적인 경향에 따르는 데이터 사이의 유사도는 낮다고 보는 것이 더 좋은 선택일 수 있는 것이죠.
마할라노비스 거리는 이처럼 변수들간의 공분산이 존재할 경우 이를 고려하여 거리를 구하는 방식입니다.
좌표 상의 거리를 구하는 방법은 단순하고 직관적이라는 장점이 있지만 아쉽게도 모든 데이터가 이런 식으로 표현되지는 않습니다. 예를 들어 여러 개의 문장들 간의 유사도를 구하고 싶다면 각 문장들을 좌표에 표현하기는 쉽지 않습니다 (최근에 많이 연구되고 있는 embedding 이라는 기법을 사용하면 가능하긴 합니다). 따라서 이런 경우엔 다른 방법을 이용해서 문장 간의 거리를 구해야 합니다.
문장 간의 거리를 구하는 가장 일반적인 방법은 아래와 같이 두 문장 사이에 차이가 나는 글자수를 세는 방법입니다 (만약 두 문장의 길이가 다르면 부족하거나 남는 글자수도 같이 계산합니다). 이것을 'Optimal matching' 알고리즘이라고 부르는데, 텍스트 문장 뿐만 아니라 일반적으로 시퀀스 데이터 사이의 거리를 구할 때 많이 사용하는 방법입니다. 참고로 아래 그림에서는 '아빠가 방에 들어간다.' 라는 문장을 기준으로 다른 세 개의 문장에서 차이가 나는 글자들을 빨간색으로 표시했습니다.
만약 아래 예시로 든 네 개 문장을 'optimal matching' 알고리즘으로 거리를 구한 후 군집 분석을 통해 두 그룹으로 분류한다면 그림의 빨간색 점선으로 된 상자처럼 '아빠가 방에 들어간다.'라는 문장과 '엄마가 방에 들어간다.' 라는 문장이 하나의 그룹으로 묶이고, '아버지께서 방에 들어가신다.'와 '어머니께서 방에 들어가신다.' 라는 문장이 하나의 그룹으로 묶일 수 있을 것입니다. 그러면 자연스럽게 존칭을 쓴 문장과 아닌 문장으로 분류되는 것이죠.
바로 직전에 소개한 거리 구하기 방법은 단순히 글자가 비슷한 문장끼리 분류하고 싶을 때 사용할 수 있습니다. 하지만 실제 문서들을 분류할 때는 좀 더 문서에 포함된 의미나 주제를 고려하여 유사도를 구해야 합니다. 이를 위해선 문서에 들어있는 주요 단어들만 골라낸 후 전체 단어 목록 중에서 어떤 단어들이 많이 포함되어 있는지를 보고 결정하는 것이 더 적절합니다. 이때 자주 사용하는 방법이 '코사인 유사도 (Cosine similarity)' 라는 방법입니다.
예를 들어 아래 그림과 같이 정치 관련 기사와 경제 관련 기사에 들어가는 주요 단어들의 목록에는 크게 차이가 있습니다. 정치 기사에는 아무래도 '정부' 나 '청와대', '국회' 등의 단어들이 자주 등장할 테고, 아래 예시의 '경제성장률' 이나 '평창올림픽' 같이 해당 시기에 정부가 관심을 갖고 있는 주요 정책과 관련된 단어들도 많이 등장하겠죠. 반면 경제 관련 기사에는 '금리', '투자', '은행' 등의 단어나 혹은 '비트코인', '가상화폐' 등의 해당 시기의 트랜드를 반영하는 단어들이 자주 등장할 것입니다.
따라서 이런 경우 미리 기사에 등장하는 모든 주요 단어에 대한 사전 목록을 만들어 놓은 후, 각 기사별로 주요 단어 목록 중 해당 기사에 등장한 단어의 빈도수를 기입합니다. 그러면 각 기사마다 주요 단어 등장 횟수에 대한 벡터를 만들 수 있습니다. 이후 이 벡터 사이의 각도에 대한 코사인 값을 구하는 것이죠. 만약 두 벡터가 같은 방향을 가리킨다면 두 벡터 간의 각도는 0도일 텐데 0도에 대한 코사인 값은 1입니다. 반대로 두 벡터의 방향이 멀어질수록 코사인 값은 1보다 작은 값이 되며 두 벡터의 방향이 직교(90도)하면 0이 됩니다 (참고로 이 예시와 같이 주요 단어의 빈도수에 대한 벡터를 만들 때는 값이 0보다 작을 수 없기 때문에 90도보다 더 각도가 벌어질 수는 없습니다).
혹시 왜 문서 간의 유사도를 구할 때 좌표 거리를 이용하지 않고 이렇게 복잡하게 코사인 유사도를 구하는지 의구심을 갖는 분이 계실지도 모릅니다. 다시 말해 위와 같이 주요 단어의 빈도수를 구하고 나면 그냥 이 값들을 이용해서 각 문서를 좌표 상의 점으로 표현한 후 두 문서의 거리를 구해도 될텐데 말이죠.
결론부터 얘기하자면, 만약 두 벡터를 비교할 때 벡터에 있는 값들의 전체 크기에 상관없이 상대적인 값들에만 관심이 있다면 코사인 유사도를 사용하며, 값의 절대적인 크기도 중요하다면 좌표 거리를 구해야 합니다. 예를 들어 아래 그림과 같이 또 다른 경제 관련 기사 C 와 정치 관련 기사 D 가 있다고 해보죠. 그런데 기사 C와 D는 정식 기사인 A, B와 달리 중요 소식만 짧게 전달하는 단신 기사여서 전체 분량이 매우 적다면 아래와 같이 벡터의 크기가 상대적으로 작을 것입니다. 이런 경우 비록 기사 C는 경제 관련 단어들이 상대적으로 많이 포함되었더라도 A에 비해 전체 단어 수가 적기 때문에 벡터의 방향은 같아도 두 점의 거리는 매우 멀게 됩니다. D역시 마찬가지로 B와 방향은 비슷해도 거리는 멀게 됩니다. 그래서 좌표 거리를 구하게 되면 C와 D는 각각 A와 B 와의 거리에 비해 둘 사이의 거리가 더 가깝게 구해집니다. 결국 좌표 거리를 이용해서 문서의 유사도를 구할 경우 문서에 포함된 주요 단어가 무엇인지에 상관없이 분량이 적은 문서들은 모두 비슷한 문서로 묶이는 문제가 발생하게 되죠.
코사인 유사도는 벡터의 크기는 고려하지 않고 방향만 이용해서 유사도를 구하기 때문에 이런 문제를 피할 수 있습니다.
마지막으로 소개할 방법은 집합 간의 유사도를 구하는 방법입니다. 예를 들어 고객이 구매한 상품 목록을 이용해서 어떤 상품들의 유사도를 측정한다고 가정해 보죠. 만약 A라는 상품을 구매한 소비자들과 B라는 상품을 구매한 소비자들의 집합을 봤을 때 두 집합 사이에 교집합의 크기가 클수록 이 두 상품은 (소비자의 구매 선호도 측면에 볼 때) 유사도가 높다고 판단할 수 있습니다. 이렇게 집합 간의 교집합 크기를 이용해서 유사도를 측정하는 방법을 '자카드 유사도 (Jaccard similarity)' 라고 합니다.
지금까지 개체 간의 유사도 혹은 거리를 측정하는 몇 가지 방법을 소개했는데요, 이 외에도 다양한 측정 방법들이 있습니다. 또한 여기서 소개한 방법들은 비교적 많이 사용하는 방법이긴 하지만 어떤 방법이 가장 좋다라는 것은 없으며 군집 분석의 목적에 따라 적절한 방법을 선택하는 것이 중요합니다.
소개한 내용을 간략히 정리하자면 다음과 같습니다.
대부분의 정형 데이터는 좌표 상의 거리 구하기를 사용할 수 있습니다. 그리고 이 경우 유클리드 거리가 가장 보편적인 방법입니다.
만약 상관성이 강한 변수쌍이 존재한다면 마할라노비스 거리를 구하는 것이 더 적절합니다.
만약 변수 간의 상관성이 없고, 데이터의 변수가 많다면 (즉, 차원이 크다면) 맨하탄 거리를 이용하는 것이 더 좋습니다.
데이터의 절대적인 크기는 중요하지 않고 변수들의 상대적인 비율만 고려해야 한다면 코사인 유사도를 사용합니다.
분석 대상이 만약 시퀀스 데이터라면 Optimal matching 과 같은 시퀀스 데이터를 위한 유사도 측정 방법을 사용합니다.
만약 데이터가 순서나 양을 갖지 않는 집합 데이터라면 자카드 유사도를 이용합니다.
이렇게 유사도를 측정하는 방식을 정하고 나면 이제 측정된 값을 이용해 군집 분석을 수행하게 됩니다. 군집 분석 방법 역시 매우 다양한데, 보통 유사도 측정 방법에 따라 거기에 맞는 방법들이 있습니다. 그럼 다음 글에서는 유사도 측정 방식 및 데이터의 특징에 따라 어떤 군집 분석 방법을 사용할 수 있는지 소개하겠습니다.