AI기본과정/AI, 머신러닝 기초

머신러닝 기초 | 군집 알고리즘(2) | k-평균 군집 알고리즘 | KMeans 클래스 | draw_변수명() 함수로 클러스터 중심 이미지 출력하기 | 최적의 k 찾기 | 비지도 학습

ANNASENA 2023. 7. 12. 08:00
728x90

 

1. 과일 데이터 불러오기

 

▶ 과일 사진 데이터 준비

!wget https://bit.ly/fruits_300 -O fruits_300.npy

: 이전에는 사과, 파인애플, 바나나에 있는 각 픽셀에 평균값을 구해서 가장 가까운 사진을 추출

→ 사과, 파인애플, 바나나 사진인 것을 미리 알고 있었기 때문에 각 과일의 평균을 구할 수 있었음

 

But 진짜 비지도 학습에서는 어떤 과일이 들어있는지 알지 못함

: k-평균 군집 알고리즘이 평균값을 자동으로 찾아줌

→ 이 평균값이 클러스터의 중심에 위치하기 때문에 클러스터 중심 또는 센트로이드(centroid)라고 부름

: k-평균 알고리즘의 작동방식을 이해하고, 사과, 파인애플, 바나나를 구분하는 비지도 학습 모델 만들어보기!

 

▶ 넘파이에서 npy 파일 로드

: load() 메서드에 파일 이름을 전달

import numpy as np

fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)

 

: k-평균 모델을 훈련하기 위해 (샘플 개수, 높이, 너비)의 3차원 배열을 (샘플 개수, 높이X너비)의 2차원 배열로 변경

 

 


2.  k-평균(k-mean) 군집 알고리즘

 

 k-평균 군집 알고리즘

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

 

사이킷런 k-평균 알고리즘 KMeans 클래스

from sklearn.cluster import KMeans

km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_2d)

: 사이킷런의 k-평균 알고리즘은 sklearn.cluster 모듈 아래 KMeans 클래스에서 구현

: n_cluster 매개변수로 클러스터 개수를 지정(클러스터 개수를 3으로 지정)

: 비지도 학습이므로 fit() 메서드에서 타깃 데이터를 사용하지 않음

 

군집된 결과를 KMeans 클래스 객체의 labels_속성에 저장

: labels_ 배열의 길이는 샘플 개수와 같음

: 배경은 각 샘플이 어떤 레이블에 해당되는지 나타냄

: n_clusters = 3으로 지정했기 때문에 labels_ 배열의 값은 0, 1, 2 중 하나

print(km.labels_)

 

▶ 레이블 0, 1, 2로 모은 샘플의 개수 확인

: 레이블값 0, 1, 2 와 레이블 순서에는 어떤 의미도 없음

: 실제 레이블 0, 1, 2가 어떤 과일 사진을 주로 모았는지 알아보려면 직접 이미지를 출력하는 것이 최선

print(np.unique(km.labels_, return_counts=True))

>> 첫 번째 클러스터(레이블0) 91개의 샘플을 모음

>> 두 번째 클러스터(레이블1) 98개의 샘플을 모음

>> 세 번째 클러스터(레이블2) 111개의 샘플을 모음

 

▶ draw_fruits() 함수로 각 클러스터의 이미지 출력해보기

: draw_fruits() 함수는 (샘플 개수, 높이, 너비)의 3차원 배열을 입력받아 가로로 10개씩 출력

: 샘플 개수에 따라 행과 열의 개수를 계산하고 figsize를 지정함

: figsize는 ratio 매개변수에 비례하여 커짐(ratio의 기본값은 1)

import matplotlib.pyplot as plt

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
    
    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()

 

▶ 레이블0, 1, 2 를 그린 결과를 보면 k-평균을 완벽하게 구현해내지는 못함

 

* 레이블0 그리기

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

 

* 레이블1 그리기

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

 

* 레이블2 그리기

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

 

 


3. 클러스터 중심

 

▶ 클러스터 중심 이미지로 출력해보기

draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3)

 

 

▶ fruits[100:101]에 대해 알아보기

 

* km.transform()

print(km.transform(fruits_2d[100:101]))

 

* km.predict()

print(km.predict(fruits_2d[100:101]))

 

* fruits[100:101]에 해당하는 과일 그려보기

draw_fruits(fruits[100:101])

 

▶ km.n_iter_

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.append(km.inertia_)

plt.plot(range(2, 7), inertia)
plt.show()

728x90