이전 글에서는 사과, 파인애플, 바나나에 있는 각 픽셀의 평균값을 구해서 분류를 했다. 그 사진이 어떤 과일인지 미리 알고 있었기 때문에 각 과일의 평균을 구할 수 있었다. 비지도 학습에서는 사진이 어떤 과일인지 알지 못하는데 이런 경우에는 어떻게 평균값을 구할 수 있을까?
K-평균 알고리즘
K-평균 알고리즘의 작동 방식은 다음과 같다.
- 무작위로 k개의 클러스터 중심을 정한다.
- 각 샘플에서 가장 가까운 클러스터 중심을 찾아 해당 클러스터의 샘플로 지정한다.
- 클러스터에 속한 샘플의 평균값으로 클러스터 중심을 변경한다.
- 클러스터 중심에 변화가 없을 때까지 2번으로 돌아가 반복한다.
이런식으로 거리를 이용해서 중심을 갱신하면서 군집을 형성한다.
KMeans
데이터를 불러오자.
(샘플 개수, 너비, 높이)로 이루어진 3차원 배열을 (샘플 개수, 너비 X 높이)로 이루어진 2차원 배열로 바꾸자.
n_clusters는 클러스터의 개수를 지정해준다. 또한 비지도 학습이므로 타깃 데이터를 이용하지 않고 훈련한다.
군집된 결과는 KMeans 클래스 객체의 labels_ 속성에 저장된다. labels_ 배열의 길이는 샘플 개수와 같다. 이 배열은 각 샘플이 어떤 레이블에 해당되는지 나타낸다.
레이블 0, 1, 2,가 어떤 과일 사진을 모았는지 알아보려면 직접 이미지를 출력하는 수밖에 없다. 각 클러스터가 몇 개의 샘플을 모았는지 확인해보자.
첫 번째 클러스터는 91개, 두 번째 클러스터는 98개, 세 번째 클러스터는 111개의 샘플을 모았다. 각 클러스터가 어떤 샘플을 모았는지 draw_fruits() 함수를 만들어서 확인해보자.
이 함수는 (샘플 개수, 너비, 높이)의 3차원 배열을 입력받아 가로로 10개씩 이미지를 출력해준다. 샘플 개수에 따라 행과 열의 개수를 계산하고 figsize를 지정한다. ratio의 기본값은 1인데 ratio에 비례하여 figsize가 커진다.
fruits[km.labels_==0]으로 쓰면 배열에서 값이 0인 위치는 True, 그렇지 않으면 False가 된다. 이는 이전에 공부했었던 불리언 인덱싱이다. 각 클러스터를 출력해보자.
레이블이 2인 클러스터는 사과와 바나나가 소량 섞여있지만 꽤 분류를 잘 해낸 듯하다.
클러스터 중심
KMeans 클래스가 찾은 클러스터 중심은 cluster_centers_ 속성에 저장되어 있다. 이 배열은 fruits_2d 샘플의 클러스터 중심이기 때문에 이미지로 출력하려면 100X100 크기의 2차원 배열로 바꿔야 한다.
KMeans 클래스는 훈련 데이터 샘플에서 클러스터 중심까지 거리로 변환해 주는 transform() 메서드를 가지고 있다.
StandardScaler에서 본 적이 있을 것이다. 이는 특성 값을 변환하는 도구로 사용할 수 있다는 의미이다.
인덱스가 100인 샘플에 transform() 메서드를 적용해보자. fit() 메서드와 마찬가지로 2차원 배열을 필요로 하기 때문에 fruits_2d[100]처럼 쓰면 (10000,) 크기의 배열이 되므로 에러가 발생한다. 슬라이싱 연산자를 사용해서 (1,10000) 크기의 배열을 전달하자.
하나의 샘플을 전달했기 때문에 반환된 배열은 크기가 (1, 클러스터 개수)인 2차원 배열이다. 이 샘플은 세 번째 클러스터 즉 레이블이 2인 클러스터까지의 거리가 가장 작은 것으로 보아 레이블 2에 속한다.
KMeans 클래스는 가장 가까운 클러스터 중심을 예측 클래스로 출력하는 predict() 메서드를 제공한다.
레이블이 2 임을 확인할 수 있다.
k-평균 알고리즘은 반복적으로 클러스터 중심을 옮기면서 최적의 클러스터를 찾는다. 알고리즘이 반복한 횟수는 KMeans 클래스의 n_iter_ 속성에 저장된다.
이처럼 클러스터 중심을 특성 공학처럼 사용해서 데이터셋을 저차원(10000->3)으로 변환할 수 있다.
n_cluster를 3으로 지정하여 클러스터의 개수를 미리 알고 설계했지만, 실전에서는 클러스터 개수를 알 수 없다. 그렇다면 n_cluster를 어떻게 지정해야 할까?
최적의 K 찾기
K-평균 알고리즘의 단점 중 하나는 클러스터 개수를 사전에 지정해야 한다는 것이다. 어떻게 하면 최적의 K를 찾을 수 있을까? 완벽한 방법은 없지만 가장 대표적인 방법인 엘보우(elbow)가 있다.
K-평균 알고리즘은 클러스터 중심과 클러스터에 속한 샘플 사이의 거리를 잴 수 있다. 이 거리의 제곱 합을 이너셔(inertia)라고 한다. 이너셔는 클러스터에 속한 샘플이 얼마나 가깝게 모여 있는지를 나타내는 값으로 생각하면 된다. 일반적으로 클러스터 개수가 늘어나면 클러스터 개개의 크기는 줄어들기 때문에 이너셔도 줄어든다. 엘보우 방법은 클러스터의 개수를 늘려가면서 이너셔의 변화를 관찰하여 최적의 클러스터 개수를 찾는 방법이다.
클러스터 개수를 증가시키면서 이너셔를 그래프로 그리면 감소하는 속도가 꺾이는 지점이 있다. 이 지점부터는 클러스터의 개수를 늘려도 클러스터에 잘 밀집된 정도가 크게 개선되지 않는다.
KMeans 클래스는 자동으로 이너셔를 계산해서 inertia_ 속성으로 제공한다. fit() 메서드로 모델을 훈련한 후 inertia_ 값을 저장하고 그래프로 출력해보자.
k=3에서 그래프의 기울기가 조금 바뀐 것을 볼 수 있다. 엘보우 지점보다 클러스터 개수가 많아지면 이너셔 변화가 줄어들면서 군집 효과도 줄어든다.
'AI > 머신 러닝(ML)' 카테고리의 다른 글
주성분 분석 (Feat. Dimensionality Reduction) (0) | 2021.09.05 |
---|---|
군집 알고리즘 (Clustering) (0) | 2021.08.24 |
트리의 앙상블 (0) | 2021.08.21 |
교차 검증과 그리드 서치(Cross Validation & Grid Search) (0) | 2021.08.18 |
결정 트리 (Decision Tree) (0) | 2021.08.16 |