<해당 글은 혼자 공부하는 머신러닝+딥러닝을 공부하고 정리한 내용입니다.>
- k-평균 군집 알고리즘은 평균값을 자동으로 찾아주는데, 이 평균값이 클러스터의 중심에 위치하기 때문에 클러스터 중심 또는 센트로이드라고 부른다.
1. k-평균 알고리즘 소개
- k-평균 알고리즘의 작동 방식
- 무작위로 k개의 클러스터 중심을 정한다.
- 각 샘플에서 가장 가까운 클러스터 중심을 찾아 해당 클러스터의 샘플로 지정한다.
- 클러스터에 속한 샘플의 평균값으로 클러스터 중심을 변경한다.
- 클러스터 중심에 변화가 없을 때까지 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로 모은 샘플의 개수를 확인
print(np.unique(km.labels_, return_counts=True))
- 각 클러스터가 어떤 이미지를 나타냈는지 그림으로 출력하기 위해 간단한 유칠리티 함수 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]))
- 이 샘플은 레이블 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 |