[혼자 공부하는 머신러닝 + 딥러닝] Chapter 06-1 군집 알고리즘

2023. 8. 29. 09:382023-2 KHUDA/ML 기초세션

이 게시물은 한빛미디어의 <혼자 공부하는 머신러닝 + 딥러닝>를 정리한 글입니다.

https://hongong.hanbit.co.kr/%ED%98%BC%EC%9E%90-%EA%B3%B5%EB%B6%80%ED%95%98%EB%8A%94-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%94%A5%EB%9F%AC%EB%8B%9D/ 

 

혼자 공부하는 머신러닝+딥러닝

혼자 공부하는 머신러닝 딥러닝, 무료 동영상 강의, 머신러닝+딥러닝 용어집을 다운로드 하세요. 포기하지 마세요! 독학으로 충분히 하실 수 있습니다. ‘때론 혼자, 때론 같이’ 하며 힘이 되겠

hongong.hanbit.co.kr

 

타깃을 모르는 비지도 학습

비지도 학습(unsupervised learning)은 타깃값이 없는 데이터를 이용해 학습하는 방식이다. 대표적인 방법은 군집(clustering)으로, 유사한 패턴을 가진 데이터를 특징 공간에서 모아 클러스터(cluster) 그룹을 만든다.

 

과일 사진 데이터 준비하기

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

import numpy as np
import matplotlib.pyplot as plt

fruits = np.load('fruits_300.npy')
print(fruits.shape)
# -> (300, 100, 100)

 

샘플의 수는 총 300개이고, 이미지 크기는 100 x 100이다.

 

첫 번째 행에 있는 픽셀 100개에 들어있는 값을 출력하면 다음과 같다.

print(fruits[0, 0, :])
# -> [  1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   2   1
# ->    2   2   2   2   2   2   1   1   1   1   1   1   1   1   2   3   2   1
# ->    2   1   1   1   1   2   1   3   2   1   3   1   4   1   2   5   5   5
# ->   19 148 192 117  28   1   1   2   1   4   1   1   3   1   1   1   1   1
# ->    2   2   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1
# ->    1   1   1   1   1   1   1   1   1   1]

이 넘파이 배열은 흑백 사진이기 때문에 0~255까지의 정숫값을 가진다.

 

plt.imshow(fruits[0], cmap='gray')
plt.show()

위의 넘파이 배열과 비교해보면, 0에 가까울수록 검게 나타나고, 높은 값을 가질수록 밝게 표시된다. cmap='gray'를 하게 되면, 우리가 집중해야 할 대상인 사과에 컴퓨터가 집중할 수 있도록 사과를 밝은색으로(255에 가깝게) 반전하여 출력해준다.

 

plt.imshow(fruits[0], cmap='gray_r')
plt.show()

cmap='gray_r'로 출력하면 흰 바탕에 검은 물체를 보여주도록 다시 반전하여 보여준다. 주의해야 할 점은 여기서 밝은 부분은 0에 가깝고 어두운 부분은 255에 가깝다.

 

fig, axs = plt.subplots(1, 2)
axs[0].imshow(fruits[100], cmap='gray_r')
axs[1].imshow(fruits[200], cmap='gray_r')
plt.show()

바나나와 파인애플 이미지도 출력했다. matplotlib의 subplots()함수를 사용하면 여러 개의 그래프를 배열처럼 쌓을수 있다. 여기서는 subplots(1, 2)처럼 하나의 행과 2개의 열을 지정했다. 반환된 axs는 2개의 서브 그래프를 담고 있는 배열이다. 

 

픽셀값 분석하기

사용하기 쉽게 fruits 데이터를 사과, 파인애플, 바나나로 각각 나눈다. 100*100 이미지를 펼쳐서 길이가 10000인 1차원 배열로 만들어준다. 이렇게 펼치면 이미지로 출력하긴 어렵지만 배열을 계산할 때 편리하다.

apple = fruits[0:100].reshape(-1, 100*100)
pineapple = fruits[100:200].reshape(-1, 100*100)
banana = fruits[200:300].reshape(-1, 100*100)

print(apple.shape)
# -> (100, 10000)

 

각 샘플의 평균값을 구하려면 배열의 mean()매서드를 사용하면 된다. 사과, 파인애플, 바나나에 대한 샘플 평균의 히스토그램을 모두 겹쳐 그려본다.

plt.hist(np.mean(apple, axis=1), alpha=0.8)
plt.hist(np.mean(pineapple, axis=1), alpha=0.8)
plt.hist(np.mean(banana, axis=1), alpha=0.8)
plt.legend(['apple', 'pineapple', 'banana'])
plt.show()

히스토그램을 보면 바나나는 픽셀 평균값만으로 사과나 파인애플과 확실히 구분된다. 바나나가 픽셀 평균값이 작은 이유는 사진에서 차지하는 영역이 작기 때문이다. 반면에 사과와 파인애플은 많이 겹쳐있어서 픽셀값만으로는 구분하기 힘들다.

 

샘플의 평균값이 아니라 픽셀별 평균값을 비교하면 사과와 파인애플도 구분할 수 있다. 세 과일은 모양이 다르기 때문에 픽셀값이 높은 위치가 조금씩 다를 것이다.

fig, axs = plt.subplots(1, 3, figsize=(20, 5))
axs[0].bar(range(10000), np.mean(apple, axis=0))
axs[1].bar(range(10000), np.mean(pineapple, axis=0))
axs[2].bar(range(10000), np.mean(banana, axis=0))
plt.show()

순서대로 사과, 파인애플, 바나나 그래프이다. 과일마다 값이 높은 구간이 다르다. 

 

픽셀 평균값을 100*100 크기로 바꿔 이미지처럼 출력하여 위 그래프와 비교해보자. 픽셀을 평균 낸 이미지를 모든 사진을 합쳐놓은 대표 이미지라 할 수 있다.

apple_mean = np.mean(apple, axis=0).reshape(100, 100)
pineapple_mean = np.mean(pineapple, axis=0).reshape(100, 100)
banana_mean = np.mean(banana, axis=0).reshape(100, 100)

fig, axs = plt.subplots(1, 3, figsize=(20, 5))
axs[0].imshow(apple_mean, cmap='gray_r')
axs[1].imshow(pineapple_mean, cmap='gray_r')
axs[2].imshow(banana_mean, cmap='gray_r')
plt.show()

 

평균값과 가까운 사진 고르기

사과 사진의 평균값인 apple_mean과 가장 가까운 사진을 절댓값 오차를 사용해 골라보자. 

abs_diff = np.abs(fruits - apple_mean)
abs_mean = np.mean(abs_diff, axis=(1, 2))
print(abs_mean.shape)
# -> (300,)

apple_index = np.argsort(abs_mean)[:100]
fig, axs = plt.subplots(10, 10, figsize=(10, 10))
for i in range(10):
    for j in range(10):
        axs[i, j].imshow(fruits[apple_index[i*10 + j]], cmap='gray_r')
        axs[i, j].axis('off')
plt.show()

apple_mean과 가장 가까운 사진 100개를 골랐더니 모두 사과가 나왔다! 완벽!