[혼공머신] 비지도 학습의 군집 알고리즘

강민우·2022년 2월 10일
0
post-thumbnail

[혼자 공부하는 머신러닝+딥러닝] 책에 기반한 정리글입니다.
전체 소스코드는 아래 Github 링크에서 확인할 수 있습니다.

Github 링크

0. 개요

비지도학습은 머신러닝의 한 종류로 훈련 데이터에 타깃이 없어, 외부의 도움 없이 스스로 학습해야 한다.

군집은 비슷한 샘플끼리 하나의 그룹으로 모으는 비지도 학습 작업이다. 군집 알고리즘으로 모은 샘플 그룹을 클러스터라고 한다.

1. 데이터 준비 및 사진 출력하기

!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, 너비 100의 넘파이 배열이다.

이를 matplotlib을 통해 그림으로 나타낼 수 있다.
cmap 매개변수를 gray로 지정하여 흑백이미지로 지정한다.

plt.imshow(fruits[0], cmap='gray')
plt.show() #흑백이지만 색이 반전되어나타남


0에 가까울수록 검게 나타나고, 255에 가까울수록 밝게 표시된다.

사실 이 이미지는 넘파이 배열로 변환할 때 색을 반전시킨 것으로, 컴퓨터 연산 처리를 위해 흰 바탕을 검은색으로, 실제 사과인 짙은 부분을 밝은색으로 바꾼 것이다.

우리 눈에 보기 좋게 출력하기 위해 cmapgray_r로 지정한다.

plt.imshow(fruits[0], cmap='gray_r')
plt.show()
# 밝은색이 0에 가깝고 어두운 색이 255에 가까움

matplotlibsubplots()함수를 이용하면 여러개의 그래프를 배열처럼 쌓을 수 있다. fig는 전체 subplots를, axs는 낱개의 그래프를 뜻한다.

subplots()의 두 매개변수는 그래프를 쌓을 행과 열을 지정한다.

fig, axs = plt.subplots(1, 2) # 여러개의 그래프를 쌓을 수 있게 도와줌
axs[0].imshow(fruits[100], cmap='gray_r')
axs[1].imshow(fruits[200], cmap='gray_r')
plt.show()

2. 픽셀값 분석하기

fruits 데이터를 사용하기 쉽게 사과, 파인애플, 바나나로 각각 나눈다.
100x100 이미지를 펼쳐 길이가 10,000인 1차원 배열로 만든다.

# 100개의 100x100 이미지를 100 x 10000 으로 reshape
apple = fruits[0:100].reshape(-1, 100*100) 
pineapple = fruits[100:200].reshape(-1, 100*100)
banana = fruits[200:300].reshape(-1, 100*100)

각 과일 이미지의 특성을 알기 위해 픽셀을 분석해본다.
여기서는, 사과, 파인애플, 바나나 배열에 있는 샘플의 픽셀 평균값을 계산한다. axis=1로 놓아 열별로 계산해본다.

print(apple.mean(axis=1))
[ 88.3346  97.9249  87.3709  98.3703  92.8705  82.6439  94.4244  95.5999
  90.681   81.6226  87.0578  95.0745  93.8416  87.017   97.5078  87.2019
  88.9827 100.9158  92.7823 100.9184 104.9854  88.674   99.5643  97.2495
  94.1179  92.1935  95.1671  93.3322 102.8967  94.6695  90.5285  89.0744
  97.7641  97.2938 100.7564  90.5236 100.2542  85.8452  96.4615  97.1492
  90.711  102.3193  87.1629  89.8751  86.7327  86.3991  95.2865  89.1709
  96.8163  91.6604  96.1065  99.6829  94.9718  87.4812  89.2596  89.5268
  93.799   97.3983  87.151   97.825  103.22    94.4239  83.6657  83.5159
 102.8453  87.0379  91.2742 100.4848  93.8388  90.8568  97.4616  97.5022
  82.446   87.1789  96.9206  90.3135  90.565   97.6538  98.0919  93.6252
  87.3867  84.7073  89.1135  86.7646  88.7301  86.643   96.7323  97.2604
  81.9424  87.1687  97.2066  83.4712  95.9781  91.8096  98.4086 100.7823
 101.556  100.7027  91.6098  88.8976]

사과 100개에 대한 픽셀 평균값을 계산했다.
바나나, 파인애플도 마찬가지로 평균값을 구한 후 히스토그램으로 그려본다.

matplotlibhist()함수를 사용해 히스토그램을 그리고, alpha 매개변수를 1보다 작게 하여 투명도를 주어 겹친 부분을 볼 수 있게 한다.
legend() 함수로 범례를 만들 수 있다.

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']) # .legend()로 범례 정하기
plt.show()


바나나는 쉽게 구별 가능하지만, 사과와 파인애플은 구별이 어렵다.

axis=0으로 두어 행별로 픽셀의 평균값을 다시 계산하여 막대그래프로 그려본다.

matplotlibbar() 함수로 그릴 수 있다.

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


사과는 사진 아래쪽으로 갈수록 값이 높아지고, 파인애플은 비교적 고르면서 높고, 바나나는 중앙의 픽셀값이 높은 특성을 가진다.

픽셀 평균값을 다시 100X100 이미지로 출력하면 명확하게 특성을 파악할 수 있다.

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


이 대표 이미지와 가까운 사진을 골라 낸다면 각 과일을 골라낼 수 있을 것이다.

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

사과 사진의 평균값과 가장 가까운 사진을 고를 것이다.
절대값 오차를 사용하는데, fruits 배열의 모든 샘플에서 apple_mean을 뺀 절대값의 평균을 사용한다.

abs_diff = np.abs(fruits - apple_mean) #300x100x100 배열
abs_mean = np.mean(abs_diff, axis=(1,2)) 
#두번째, 세번째 차원 지정하여 300x1의 배열 만들어짐

np.argsort() 함수는 작은 것부터 큰 순서대로 나열한 인덱스를 반환한다.

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[10*i + j]], cmap='gray_r')
    axs[i, j].axis('off') #축 없애 이미지 깔끔하게 보이기

plt.show()

4. 한계

여기서는 사과, 파인애플, 바나나가 있다는 것을 알고있었다.
즉, 타깃값을 알고 있었기 때문에 픽셀의 평균값을 계산해서 가장 가까운 과일을 찾을 수 있었지만, 일반적인 비지도 학습에서는 타깃값을 모르기 때문에 샘플의 평균값을 미리 구할 수 없다는 단점이 있다.

profile
어제보다 성장한 오늘

0개의 댓글