티스토리 뷰

728x90

비지도 학습

 

현실의 대부분의 데이터들은 레이블이 없는 경우가 많다. 사실 어찌보면 당연하다. 예를 들어보자. Youtube 서비스의 추천 알고리즘을 개발한다고 하자. Youtube 서비스를 이용하는 사람들의 접속, 동영상 시청 여부, 시간등에 대한 데이터는 구하기 쉬울 것이다. 하지만 이 데이터를 가지고 어떻게 사용자를 분류해 각 사용자에 맞는 동영상을 추천할까? 동영상을 추천하는 작업은 사용자를 분류한 이후의 별개의 작업이므로 여기서는 어떻게 올바르게 사용자를 분류할 수 있을 지에 대해 생각해보자. 

 

사용자의 Youtube 사이트, 어플 접속, 동영상 시청 여부에 대한 데이터 셋에는 각 사용자들을 어떻게 분류해야하는 지에 대한 정답이 표면적으로 나와있지 않을 것이다. 즉 지도 학습이 가능한 데이터 셋과 달리 레이블이 포함되어 있지 않을 것이다. 따라서 직접 레이블을 사람의 손 이를 테면 사용자의 접속 시간이나 특정 동영상 시청 여부와 같은 데이터를 보고 레이블을 올바르게 기입할 수 있는 ‘전문가’의 손이 필요하다. 하지만 이 또한 이상적인 해결책이 될 수 없다. 하루에 Youtube에 접속하는 사람만 ~에 이른다고 한다. 이를 어떻게 수작업으로 레이블을 기입할 수 있을까?

 

답은 여러가지가 있다. 하지만 여기서는 그 중에서 군집(클러스터링)에 대해 알아본다.

 

군집

간단히 말해 비슷한 사용자끼리 같은 그룹으로 묶는 것을 말한다. 아래와 같은 데이터 셋을 얻었다고 하자. 레이블이 없는 데이터 셋이다.

 

눈으로 봐도 왼쪽 아래의 데이터들은 하나로 군집화할 수 있을 것 같다. 마찬가지로 오른쪽 위의 데이터들도 하나로 군집화할 수 있을 것 같다. 여기서 문제가 되는 것은 이런 식으로 군집화하는 것이 올바른지 여부다. 군집화의 성능은 어떻게 측정하는가? 군집화의 성능은 군집화 알고리즘 마다 다르게 측정된다. 또한 군집화 알고리즘 마다의 ‘군집’에 대한 정의가 다르다. 가령 k-Means 알고리즘은 센트로이드라고 하는 특정 데이터 포인트를 중심으로 모인 샘플을 찾고, 어떤 알고리즘은 샘플이 밀집되어 연속된 영역을 찾는다.

 

k-Means

먼저 대표적인 군집화 알고리즘인 k-Means 알고리즘을 살펴본다. 이 알고리즘은 몇 번의 반복으로 빠르게 샘플들을 군집화한다. 대략 다음과 같은 방식에 의해 군집화가 이루어진다. 먼저 지정한 클러스터의 개수 만큼의 센트로이드를 데이터 포인트 중에서 랜덤으로 선택한다. 이후 각 샘플에 레이블을 할당한다. 그 다음 센트로이드를 업데이트한다. 이 과정을 센트로이드가 업데이트 후에도 바뀌지 않을 때 까지 반복한다. 

 

이 알고리즘은 하드 군집(hard clustering)이라는, 샘플을 클러스터에 할당하는 것이 아닌 클러스터마다 샘플에 점수를 부여하는 소프트 군집 방식으로 작동한다. 클러스터는 센트로이드를 기준으로 구성되며 따라서 각 클러스터에는 하나의 센트로이드가 존재한다. 점수는 각 센트로이드와 샘플들의 거리가 된다. 

 

아래와 같은 데이터 셋이 주어졌다고 하자.

눈으로 보기에 5개의 군집이 보인다. 사이킷런의 k-means 알고리즘을 사용해 실제로 군집화해보자.

 

클러스터의 개수를 5로 지정한다. 위 데이터 셋처럼 눈으로도 쉽게 군집을 판별할 수 있기 때문에 이렇게 지정한 것이다. 데이터 셋이 이렇게 원형이 아니라 타원형인 경우도 많고 군집마다 밀도나 크기가 크게 차이 나는 경우도 많아서 눈으로 확인하는 데에는 한계가 있다.

 

군집화가 이루어진 후 각 샘플의 레이블은 군집의 인덱스이다.(0번째 군집, 1번째 군집, ...)

 

알고리즘이 찾은 센트로이드도 확인할 수 있다. 센트로이드는 각 클러스터의 중심 데이터 포인트를 말한다. 예를 들어 아래의 첫번째 센트로이드는 x1의 값이 -2.8, x2의 값이 1.3인 곳에 위치해 있다.

 

샘플과 센트로이드 간의 평균 제곱 거리가 매 반복마다 작아지기 때문에 수렴하는 것이 보장되지만 센트로이드를 선택하는 과정이 무작위이기 때문에 지역 최적점에 수렴할 수 있다. 때문에 다른 군집화 알고리즘을 먼저 적용해 센트로이드를 알아낸 후 k-means 알고리즘을 사용하거나 시행착오를 거쳐 가장 좋은 솔루션을 선택하는 방법으로 위 문제를 해결할 수 있다. 최적의 솔루션은 각 샘플과 센트로이드의 평균 제곱 거리인 inertia의 비교를 통해 구한다.

 

사이킷런에서는 단순히 n_init 매개변수로 반복 측정할 횟수를 지정하면 된다. 시행횟수중 최적의 솔루션(inertia 값이 가장 낮은)을 반환한다. 여기서 algorithm 매개변수는 기본 값이 auto이지만 아래처럼 일반 알고리즘인 full을 지정하지 않는다면 더 효율적이나 메모리 소모가 큰 elkan 알고리즘을 사용한다.

 

전체 데이터셋을 사용해 반복하지 않고 각 반복마다 미니배치를 사용해 센트로이드를 조금씩 이동하는 MiniBatch k-means를 사용하면 일반적 알고리즘보다 3~4배 가량 빠르다.

 

사이킷런에서 아래와 같이 사용한다.

이 알고리즘은 일반 알고리즘보다 빠르지만 특히 클러스터의 개수가 많으면 inertia는 더 나쁘다.

 

최적의 클러스터 개수

최적의 센트로이드는 inertia 측정을 통해 구한다. 그러면 최적의 클러스터 개수는 어떻게 구할까? 가장 작은 inertia를 선택한다면 일반적으로 더 좋지 못한 결과를 보인다. inertia는 샘플과 센트로이드 사이의 거리이기 때문에 센트로이드가 많아질수록 이 값은 더 적어질 것 이다. 즉 클러스터 개수가 증가하면 inertia는 일반적으로 더 줄어든다. 이 관점에 따르면 샘플 개수만큼 클러스터 개수가 있다면 inertia는 0으로 제일 좋은 결과를 보일 것이나 올바른 군집화라 볼 수 없다. inertia가 빠르게 감소하다가 감소 폭이 적어지는 지점(클러스터 개수)를 선택하는 방법도 있다.

하지만 일반적으로 silhouette(실루엣) 점수를 이용한다. 이 값은 모든 샘플에 대한 실루엣 계수의 평균으로, 실루엣 계수는 (b - a) / max(a,b)로 구한다. 여기서 a, b는 각각 클러스터 내부의 평균 거리, 가장 가까운 클러스터의 샘플까지 평균 거리이다. 값은 -1과 1사이이며 1에 가까울 수록 자신의 클러스터 안에 잘 속해있고 다른 클러스터와는 멀리 떨어져 있다.

 

사이킷런에서는 아래와 같이 사용한다.

 

k-means의 한계

k-means 알고리즘은 아래와 같이 데이터 셋이 원형(혹은 구형)이 아니거나 클러스터의 크기나 밀집도가 서로 다른 경우 잘 작동하지 않는다. 따라서 입력 특성의 스케일을 맞춰 클러스터가 길쭉해지는 것을 방지하는 것이 좋다.

센트로이드를 올바르게 사전 지정한 kmeans_good과 그렇지 않은 kmeans_bad 두 모델을 생성한 후 비교한다.

inertia는 더 나쁜데도 불구하고 왼쪽 모델이 오른쪽보다는 더 좋은 모델임을 확인할 수 있다. 하지만 왼쪽 모델 역시 가운데에 위치한 타원형의 데이터 셋의 윗 부분이 원형 데이터 셋의 군집 안에 잘못 포함되어 있음을 볼 수 있다.

댓글