[혼자공부하는 머신러닝 + 딥러닝] 13_군집 알고리즘
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()
- 첫 번째 이미지는 사과처럼 보인다. 그림에서 알 수 있는것 처럼 첫 번쨰 행이 출력한 배열 값에 해당한다. 0 에 가까울 수록 검게 나타나고 높은 값은 밝게 표시된다.
- 그림이 우리가 아는 흑백의 사진과는 조금 다른 형태를 띄는 것을 확인할 수 있다. 자연스럽게 만드려면 ‘gray_r’을 이용하면 된다. 그렇게 하면 값이 낮을수록 밝아지고 높을수록 짙어진다.
- 해당 데이터에는 사과, 바나나, 파인애플이 각각 100개씩 포함되어있다. 바나나와 파인애플도 출력해보아야 한다.
plt.imshow(fruits[0], cmap='gray_r')
plt.show()
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>
- 데이터 준비가 모두 끝났다. 각각 과일을 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()
- 히스토그램을 살펴보니 바나나 사진의 평균값은 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>
- 순서대로 사과, 파인애플, 바나나 그래프이다. 각 과일마다 값이 높은 구간이 다른 형태를 보인다. 이 픽셀 평균값을 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>
- 세 과일은 픽셀 위치에 따라 값의 크기가 차이가 난다. 따라서 이 대표 이미지와 가까운 사진을 골라낼 수 있으면 사과, 파인애플, 바나나를 구분 할 수 있을 것이다.
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()
4. 마치며
- 100개 모두 사과인 결과를 얻었다.
- 흑백 사진에 있는 픽셀값을 사용해 과일 사진을 모으는 작업을 진행해 보았다. 이렇게 비슷한 샘플끼리 그룹으로 모으는 작업을 군집이라고 한다. 군집은 대표적인 비지도 학습 작업 중 하나이다. 군집 알고리즘에서 만든 그룹을 클러스터라고 부른다.
- 이번 시간에는 어떤 타깃이 존재하는지 알고 있었다. 하지만 실제로 비지도 학습에서는 타깃값을 모르기 때문에 샘플의 평균값을 미리 구할 수 없다. 타깃값을 모르면 어떻게 세 과일의 평균값을 찾을 수 있을까에 대한 해답은 다음시간에 이어나가도록 하겠다.
- 저번시간까지 지도학습 알고리즘들을 꾸준히 다뤄왔다. 이번시간에는 비지도 학습 알고리즘 중 군집 알고리즘에 대해 배워보았다. 과일 데이터를 통해 분류를 수행하는 과정을 통해 군집 알고리즘을 이해하는데 도움을 받을 수 있었다. 점점 더 머신러닝과 딥러닝의 매력에 빠져드는것 같아서 뿌듯하기도 하면서, 이해량보다 공부량이 월등히 적어서 이전에 공부한 것들도 다시 복습해야겠다.
Leave a comment