본문 바로가기

데이터/머신러닝

Chapter 06-2 k-평균 알고리즘

<해당 글은 혼자 공부하는 머신러닝+딥러닝을 공부하고 정리한 내용입니다.>

 

  • k-평균 군집 알고리즘은 평균값을 자동으로 찾아주는데, 이 평균값이 클러스터의 중심에 위치하기 때문에 클러스터 중심 또는 센트로이드라고 부른다.

 

 

1. k-평균 알고리즘 소개 

  • k-평균 알고리즘의 작동 방식
    1. 무작위로 k개의 클러스터 중심을 정한다.
    2. 각 샘플에서 가장 가까운 클러스터 중심을 찾아 해당 클러스터의 샘플로 지정한다.
    3. 클러스터에 속한 샘플의 평균값으로 클러스터 중심을 변경한다.
    4. 클러스터 중심에 변화가 없을 때까지 2번으로 돌아가 반복한다.

 

  • k-평균 알고리즘은 처음에는 랜덤하게 클러스터 중심을 선택하고 점차 가까운 샘플의 중심으로 이동하는 간단한 알고리즘

 

 

2. KMeans 클래스

import numpy as np

fruits = np.load('fruits_300.npy')

#(샘플 개수, 너비, 높이)크기의 3차원 배열을 (샘플 개수, 너비*높이)크기를 가진 2차원 배열로 변경
fruits_2d = fruits.reshape(-1, 100*100)

from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)

#비지도 학습이므로 fit메서드에서 타깃 데이터를 사용하지 않는다.
km.fit(fruits_2d)

 

  • 군집된 결과는 KMeans 클래스 객체의 labels_ 속성에 저장된다. labels_ 배열의 길이는 샘플 개수와 같다. 이 배열은 각 샘플이 어떤 레이블에 해당되는지 나타낸다. 
print(km.labels_)

실제 레이블 0,1,2가 어떤 과ㅏ일 사진을 주로 모았는지 알아보려면 직접 이미지를 출력해야 함.

 

 

  • 그 전에 레이블 0,1,2로 모은 샘플의 개수를 확인
print(np.unique(km.labels_, return_counts=True))

첫 번째 클러스터(레이블 0)가 91개의 샘플을 모았다.

 

 

  • 각 클러스터가 어떤 이미지를 나타냈는지 그림으로 출력하기 위해 간단한 유칠리티 함수 draw_fruits()를 만든다.
import matplotlib.pyplot as plt

#(샘플 개수, 너비, 높이)의 3차원 배열을 입력받아 가로로 10개씩 이미치를 출력
def draw_fruits(arr, ratio=1):
    n = len(arr)    # n은 샘플 개수
    # 한 줄에 10개씩 이미지를 그린다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산
    rows = int(np.ceil(n/10))
    # 행이 1개 이면 열 개수는 샘플 개수, 그렇지 않으면 10개
    cols = n if rows < 2 else 10
    
    #샘플 개수에 따라 행과 열의 개수를 계산하고 figsize를 지정한다. 
    #figsize는 ratio매개변수에 비례하여 커진다. radio의 기본값은 1
    fig, axs = plt.subplots(rows, cols, figsize=(cols*ratio, rows*ratio), squeeze=False)
    for i in range(rows):
        for j in range(cols):
            if i*10 + j < n:    # n개까지만 그린다.
                axs[i, j].imshow(arr[i*10 + j], cmap='gray_r')
            axs[i, j].axis('off')
    plt.show()

 

#km.labels_==0로 쓰면 배열에서 값이 0인 위치는 True 나머지는 False(불리언 인덱싱)
draw_fruits(fruits[km.labels_==0])

 

 

  • 나머지 두 클러스터
draw_fruits(fruits[km.labels_==1])

 

 

draw_fruits(fruits[km.labels_==2])

 

 

 

3. 클러스터 중심

  • 최종적으로 찾은 클러스터 중심은 cluster_centers_ 속성에 저장, 이 배열은 fruits_2d 샘플의 클러스터 중심이기 때문에 이미지로 출력하려면 100×100 크기의 2차원 배열로 바꿔야 한다.
draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3)

 

 

  • transform메서드는 훈련 데이터 샘플에서 클러스터 중심까지 거리로 변환

 

  • 인덱스가 100인 샘플에 transform()메서드를 적용하려면 2차원 배열이 필요, (1,10000)크기의 배열 전달해야 한다.
print(km.transform(fruits_2d[100:101]))

하나의 샘플을 전달했기 때문에 반환된 배열은 크기가 (1, 클러스터 개수)인 2차원 배열, 첫 번째 클러스터가 첫 번째 원소.

 

 

  • 이 샘플은 레이블 2에 속한다.

 

  • 예측 클래스
#predict 메서드 = 가장 가까운 클러스터 중심을 예측 클래스로 출력
print(km.predict(fruits_2d[100:101]))

 

 

  • 샘플 확인
draw_fruits(fruits[100:101])

 

 

  • 알고리즘이 반복한 횟수확인
print(km.n_iter_)

 

 

  • 지금까지는 클러스터의 개수를 지정했는데, 그렇다면 클러스터의 개수를 알 수 있는 방법은?

 

 

 

4. 최적의 k 찾기

  • 엘보우 방법 : 클러스터 개수를 늘려가면서 이너셔의 변화를 관찰하여 최적의 클러스터 개수를 찾는 방법

 

  • 이너셔 : 클러스터 중심과 클러스터에 속한 샘플 사이의 거리의 제곱 합. 클러스터에 속한 샘플이 얼마나 가깝게 모여 있는지를 나타내는 값. 일반적으로 클러스터 개수가 늘어나면 클러스터 개개의 크기는 줄어들기 때문에 인어셔도 줄어든다. 

 

  • 클러스터 개수를 증가시키면서 이너셔를 그래프로 그리면 감소하는 속도가 꺾이는 지점이 있는데, 이 지점부터는 클러스터 개수를 늘려도 클러스터에 잘 밀집된 정도(이너셔)가 크게 개선되지 않는다. 이 모습이 팔꿈치와 닮아 엘보우 방법이라고 부른다.
inertia = []
for k in range(2, 7):
    km = KMeans(n_clusters=k, random_state=42)
    #모델훈련
    km.fit(fruits_2d)
    
    #이너셔를 자동으로 계산에 inertia_속성으로 제공
    inertia.append(km.inertia_)

#마지막으로 inertia리스트에 저장된 값을 그래프로 출력
plt.plot(range(2, 7), inertia)
plt.xlabel('k')
plt.ylabel('inertia')
plt.show()

 

 

  • 엘보우 지점보다 클러스터 개수가 많아지면 이너셔의 변화가 줄어들면서 군집 효과도 줄어든다. 하지만 이 그래프는 해당 지점이 명확하지는 않다.

 

 

5. 과일을 자동으로 분류하기

  • k-평균 알고리즘은 각 샘플에서 각 클러스터까지의 거리를 하나의 특성으로 활용할 수도 있다. 이를 위해 transform()메서드 제공, predict메서드는 새로운 샘플에 대해 가장 가까운 클러스터를 예측값으로 출력

 

  • k-평균 알고리즘은 사전에 클러스터 개수를 미리 지정해야하는데, 데이터를 직접 확인하지 않는 이상 어려워 이너셔를 사용하는 엘보우 방법을 활용한다.

 

  • KMeans 클래스는 자동으로 이너셔를 계산하는 inertia_속성을 제공하고 클러스터 개수를 늘리면서 반복해 이너셔가 줄어드는 속도가 꺾이는 지점을 최적의 클러스터 개수로 결정

 

'데이터 > 머신러닝' 카테고리의 다른 글

Chapter 06-3 주성분 분석  (0) 2022.03.15
Chapter 06-1 군집 알고리즘  (0) 2022.03.13
Chapter 05-3 트리의 앙상블  (0) 2022.03.12
Chapter 05-2 교차검증과 그리드 서치  (0) 2022.03.10
Chapter 05-1 결정 트리  (0) 2022.03.10