12. 군집 알고리즘

  • 이전시간까지 다양한 머신러닝 알고리즘을 사용해 물고기 데이터와, 와인분류 데이터를 활용해 실습을 진행했다.
  • 이번시간에는 타깃을 알지 못하는 데이터를 활용해 분류작업을 진행해야 한다. 이때 비지도 학습을 이용해야 한다.
  • 비지도 학습은 사람이 가르쳐 주지 않아도 데이터에 있는 무언가를 스스로 학습하는것을 말한다.

1. 들어가며

  • 이번에는 캐글에 공개된 과일 흑백 사진 데이터를 활용할 것이다. 이 데이터는 넘파이 기본 저장 포맷인 npy파일로 저장되어 있다. 이 파일을 불러오도록 한다.
import numpy as np
import matplotlib.pyplot as plt

fruits = np.load('/Users/janghyeseong/Downloads/fruits_300.npy')

print(fruits.shape)
(300, 100, 100)
  • 이 배열의 첫 번째 차원(300)은 샘플의 개수를 나타내고, 두 번째 차원(100)은 이미지 높이, 세 번째 차원(100)은 이미지의 너비를 나타낸다. 이미지 크기는 100x100이며, 각 픽셀은 넘파이 배열의 원소 하나에 대응하기 때문에 배열의 크기 또한 100x100이다.
  • 먼저 첫 번째 행을 출력해 보자. 3차원 배열이기 때문에 처음 2개의 인덱스를 0 으로 지정하고 마지막 인덱스는 지정하지 않거나 슬라이싱 연산자를 써서 첫 번째 이미지의 첫 번째 행을 모두 선택 할 수 있다.
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]
  • 첫 번째 행에 있는 픽셀 100개에 들어 있는 값을 출력했다. 이 넘파이 배열은 흑백사진을 담고 있으므로 0~255의 정숫값을 가진다. 맷플롯립의 먼저 imshow()함수를 이용해 시각화를 진행하자.
plt.imshow(fruits[0], cmap='gray')
plt.show()

output_8_0

  • 첫 번째 이미지는 사과처럼 보인다. 그림에서 알 수 있는것 처럼 첫 번쨰 행이 출력한 배열 값에 해당한다. 0 에 가까울 수록 검게 나타나고 높은 값은 밝게 표시된다.
  • 그림이 우리가 아는 흑백의 사진과는 조금 다른 형태를 띄는 것을 확인할 수 있다. 자연스럽게 만드려면 ‘gray_r’을 이용하면 된다. 그렇게 하면 값이 낮을수록 밝아지고 높을수록 짙어진다.
  • 해당 데이터에는 사과, 바나나, 파인애플이 각각 100개씩 포함되어있다. 바나나와 파인애플도 출력해보아야 한다.
plt.imshow(fruits[0], cmap='gray_r')
plt.show()

output_10_0

fig, axs = plt.subplots(1,2)
axs[0].imshow(fruits[100], cmap='gray_r')
axs[1].imshow(fruits[200], cmap='gray_r')
<matplotlib.image.AxesImage at 0x1258e48b0>

output_11_1

  • 데이터 준비가 모두 끝났다. 각각 과일을 100개씩 담고 있다. 각 과일 사진의 평균을 내서 차이를 살펴보도록 하자.

2. 픽셀값 분석하기

  • 해당 데이터를 넘파이 배열을 나눠서 1차원 배열로 만들어주자. 계산을 용이하게 만들기 위해서 이다.
  • fruits 배열에서 순서대로 100개씩 선택하기 위해 슬라이싱 연산자를 사용한다. reshape() 메서드를 사용해 두 번째 차원(100)과 세 번째 차원(100)을 10,000으로 합친다. 첫 번째 차원을 -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)
  • 각각의과일의 배열크기는 (100, 10000)이다. 아래에서 확인해볼 수 있다.
print(apple.shape)
(100, 10000)
  • 각각의 배열의 평균을 구해보도록 하자. mean() 메서드를 이용해 평균을 구할 수 있다. 샘플마다 픽셀의 평균값을 계산해야 하기 때문에 axis=0으로 하면 첫 번째 축인 행을 따라 계산한다. axis=1로 지정하면 두 번째 축인 열을 따라 계산한다.
  • 우리는 샘플을 가로로 나열했기때문에 열을 기준으로 계산을 해야한다. 따라서 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개에 대한 픽셀값의 평균을 게산했다. 이를 히스토그램을 통해 어떨게 평균값이 분포되어 있는지 알 수 있다.
  • 맷플롯립의 hist()함수를 사용하면 히스토그램을 그릴수 있다.
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()

output_21_0

  • 히스토그램을 살펴보니 바나나 사진의 평균값은 40 아래에 집중되어있는 모습을 보인다. 사과와 바나나는 90~100사이에 가장 많은 수가 모여있는 것을 확인할 수 있다. 픽셀값으로도 이렇게 대략적인 구분이 가능하다.
  • 샘플이 아닌 전체 픽셀에 대해 평균을 구해볼 수 도 있을 것이다. 어쩌면 샘플로써 구분하지 못한 파인애플과 사과의 분포의 차이를 발견할지도 모르기 때문이다.
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))
<BarContainer object of 10000 artists>

output_23_1

  • 순서대로 사과, 파인애플, 바나나 그래프이다. 각 과일마다 값이 높은 구간이 다른 형태를 보인다. 이 픽셀 평균값을 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')
<matplotlib.image.AxesImage at 0x13504e460>

output_25_1

  • 세 과일은 픽셀 위치에 따라 값의 크기가 차이가 난다. 따라서 이 대표 이미지와 가까운 사진을 골라낼 수 있으면 사과, 파인애플, 바나나를 구분 할 수 있을 것이다.

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

  • 사과 사진의 평균값인 apple_mean과 가장 가까운 사진을 골라보자. 절댓값 오차를 사용해 구해보자. fruits 배열에 있는 모든 샘플에서 apple_mean을 뺀 절댓값의 평균을 계산하면 된다.
  • abs()함수를 이용해 절댓값 계산이 가능하다. 다음 코드에서 abs_diff는 (300, 100, 100)크기의 배열이다. 각 샘플에 대한 평균을 구하기 위해 axis에 두 번째, 세 번째 차원을 모두 지정했다. 이렇게 계산한 abs_mean은 각 샘플의 오차 평균이기 때문에 크기가 (300,)인 1차원 배열이다.
abs_diff = np.abs(fruits - apple_mean)
abs_mean = np.mean(abs_diff, axis=(1,2))
print(abs_mean.shape)
(300,)
  • 이 값이 가장 작은 순서대로 100개를 골라보자. 즉 오차가 가장 작은 샘플 100개를 고르는 것이다. np.argsort() 함수는 작은 것에서 큰 순서대로 나열한 abs_mean 배열의 인덱스를 반환한다. 이 인덱스 중에서 처음 100개를 선택해 10x10 격자로 이루어진 그래프는 그려보자.
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()

output_31_0

4. 마치며

  • 100개 모두 사과인 결과를 얻었다.
  • 흑백 사진에 있는 픽셀값을 사용해 과일 사진을 모으는 작업을 진행해 보았다. 이렇게 비슷한 샘플끼리 그룹으로 모으는 작업을 군집이라고 한다. 군집은 대표적인 비지도 학습 작업 중 하나이다. 군집 알고리즘에서 만든 그룹을 클러스터라고 부른다.
  • 이번 시간에는 어떤 타깃이 존재하는지 알고 있었다. 하지만 실제로 비지도 학습에서는 타깃값을 모르기 때문에 샘플의 평균값을 미리 구할 수 없다. 타깃값을 모르면 어떻게 세 과일의 평균값을 찾을 수 있을까에 대한 해답은 다음시간에 이어나가도록 하겠다.
  • 저번시간까지 지도학습 알고리즘들을 꾸준히 다뤄왔다. 이번시간에는 비지도 학습 알고리즘 중 군집 알고리즘에 대해 배워보았다. 과일 데이터를 통해 분류를 수행하는 과정을 통해 군집 알고리즘을 이해하는데 도움을 받을 수 있었다. 점점 더 머신러닝과 딥러닝의 매력에 빠져드는것 같아서 뿌듯하기도 하면서, 이해량보다 공부량이 월등히 적어서 이전에 공부한 것들도 다시 복습해야겠다.

Categories:

Updated:

Leave a comment