혼자 공부하는 머신러닝+딥러닝 책을 바탕으로 공부한 내용입니다.
CH6 비지도 학습 ②
과일을 자동으로 분류하기
k-평균 알고리즘의 작동 방식을 이해하고 타깃값을 모를 때
과일 사진을 자동으로 모으는 비지도 학습 모델을 만들어보자
▶ K-평균 알고리즘 소개
- 무작위로 k개의 클러스터 중심을 정한다
- 각 샘플에서 가장 가까운 클러스터 중심을 찾아 해당 클러스터의 샘플로 지정한다
- 클러스터에 속한 샘플의 평균값으로 클러스터 중심을 변경한다
- 클러스터 중심에 변화가 없을 때까지 2번으로 돌아가 반복한다
k-평균 알고리즘은 처음에는 랜덤하게 클러스터 중심을 선택하고 점차 가까운 샘플의 중심으로 이동하는 알고리즘이다
클러스터 중심
- k-평균 알고리즘이 만든 클러스터에 속한 샘플의 특성 평균값
- 센트로이드라고도 부름
- 가장 가까운 클러스터 중심을 샘플의 또 다른 특성으로 사용하거나 새로운 샘플에 대한 예측으로 활용할 수 있음
▶ KMeans 클래스
먼저 데이터를 불러와 3차원 배열을 2차원 배열로 변경해주자
# 데이터 불러오기
import wget
url = "https://bit.ly/fruits_300_data"
wget.download(url)
# 2차원 배열로 변경
import numpy as np
fruits = np.load('fruits_300_data')
fruits_2d = fruits.reshape(-1, 100*100)
KMeans 클래스에서 n_clusters로 클러스터 개수를 지정해준다.
# K-평균 알고리즘
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_2d)
# 군집된 결과 확인
print(km.labels_)
# 레이블 0, 1, 2 개수 확인
print(np.unique(km.labels_, return_counts=True))
- 비지도 학습이므로 fit() 메서드에서 타깃 데이터를 사용하지 않는다.
- 각 클러스터가 111, 98, 91개의 샘플을 모았다.
- 레이블 값과 레이블 순서는 아무 의미도 없다.
각 클러스터가 어떤 이미지를 나타냈는지 그림으로 출력해주는 draw_fruits() 함수를 만들어보자
# 클러스트가 어떤 이미지를 나타냈는지 그림 출력 함수 만들기
import matplotlib.pyplot as plt
def draw_fruits(arr, ratio=1):
n = len(arr) # 샘플 개수
rows = int(np.ceil(n/10)) # 한 줄에 10개씩
# 행이 1개면 열 개수는 샘플 개수, 아니면 10개
cols = n if rows < 2 else 10
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()
- draw_fruits() 함수는 (샘플 개수, 너비, 높이)의 3차원 배열을 입력받아 가로로 10개씩 이미지를 출력한다
이 함수를 사용해 각 레이블에 해당하는 과일 사진을 그려보자
draw_fruits(fruits[km.labels_==0])
draw_fruits(fruits[km.labels_==1])
draw_fruits(fruits[km.labels_==2])
- k-평균 알고리즘이 완벽하게 구별하진 못했지만 타깃 레이블을 제공하지 않았음에도 스스로 비슷한 샘플들을 잘 모은 것 같다
▶ 클러스터 중심
KMeans 클래스가 최종적으로 찾은 클러스터 중심은 cluster_centers_ 속성에 저장되어 있다.
이 배열은 fruits_2d 샘플의 클러스터 중심이므로 이미지로 출력하기 위해 2차원 배열로 바꿔주자
# 클러스트 중심 이미지로 출력
draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3)
- 앞서 봤던 사과, 바나나, 파인애플의 픽셀 평균값을 출력했던 것과 매우 비슷함을 알 수 있다.
KMeans 클래스는 훈련 데이터 샘플에서 클러스터 중심까지 거리로 변환해주는 transform() 메서드를 가지고 있다
또, 가장 가까운 클러스터 중심을 예측 클래스로 출력하는 predict() 메서드를 가지고 있다.
인덱스가 100인 샘플에 적용해보자
# 인덱스가 100인 샘플에 transform() 적용
print(km.transform(fruits_2d[100:101]))
# 가장 가까운 클러스터 중심을 예측 클래스로
print(km.predict(fruits_2d[100:101]))
- 0번째 클러스터까지의 거리가 가장 작으므로 0으로 예측하고 있다.
위에서 레이블 0은 파인애플이었으므로 샘플도 파인애플 일 것으로 보인다
# 그려보기
draw_fruits(fruits[100:101])
- 확인해보니 파인애플이 맞다!
k-평균 알고리즘은 최적의 클러스터를 찾기 위해 반복적으로 클러스터 중심을 옮긴다
알고리즘이 반복한 횟수는 KMeans 클래스의 n_iter_ 속성에 저장된다
# 알고리즘 반복 횟수
print(km.n_iter_) #4
▶ 최적의 k 찾기
k-평균 알고리즘의 단점 중 하나는 클러스터 개수를 사전에 지정해야한다는 것이다.
적절한 클러스터 개수를 찾기 위한 대표적인 방법으로 엘보우 방법이 있다.
- 이너셔는 클러스터 중심과 샘플 사이 거리의 제곱 합
- 클러스터 개수에 따라 이너셔 감소가 꺾이는 지점이 적절한 클러스터 개수 k가 된다
- 이 그래프의 모양을 따서 엘보우 방법이라고 부른다.
과일 데이터셋을 사용해 이너셔를 계산해보자.
KMeans 클래스는 자동으로 이너셔를 계산해서 inertia_ 속성으로 제공한다
inertia = []
for k in range(2, 7):
km = KMeans(n_clusters=k, random_state=42)
km.fit(fruits_2d)
inertia.append(km.inertia_)
# 그래프로 출력
plt.plot(range(2, 7), inertia)
plt.xlabel('k')
plt.ylabel('inertia')
plt.show()
- k=3에서 그래프의 기울기가 조금 바뀐 것을 확인할 수 있다.
▶ 정리
k-평균 알고리즘
- 비교적 간단하고 속도가 빠르며 이해하기 쉽다
- 사전에 클러스터 개수를 미리 지정해야 한다.
- 최적의 클러스터 개수 k를 알아내는 한 가지 방법은 이너셔를 사용하는 것이다.
- 클러스터 개수를 늘리면서 반복하여 KMeans 알고리즘을 훈련하고 이너셔가 줄어드는 속도가 꺾이는 지점을 최적의 클러스터 개수로 결정한다.
'Python > ML & DL 공부' 카테고리의 다른 글
[DL] 07-1 인공 신경망 (0) | 2022.03.20 |
---|---|
[ML] 06-3 주성분 분석 (0) | 2022.03.12 |
[ML] 06-1 군집 알고리즘 (0) | 2022.03.12 |
[ML] 05-3 트리의 앙상블 (0) | 2022.03.11 |
[ML] 05-2 교차 검증과 그리드 서치 (0) | 2022.03.11 |