Clustering Algorithm¶
과일 사진 데이터 준비하기¶
- 코랩 코드 셀에서 '!' 문자로 시작하면 코랩은 이후 명령을 파이썬 코드가 아니라 리눅스 쉘 명령으로 이해한다.
- wget 명령은 원격 주소에서 데이터를 다운로드하여 저장한다.
- -O 옵션에서 저장할 파일 이름을 지정할 수 있다.
- 아래는 juypyter notebook에서 사용하기 위해 stack overflow에 검색하여 다른 코드를 사용한 것이다.
In [1]:
import urllib.request
url = 'https://bit.ly/fruits_300_data'
filename = 'fruits_300.npy'
urllib.request.urlretrieve('https://bit.ly/fruits_300_data', 'fruits_300.npy')
Out[1]:
In [2]:
import numpy as np
import matplotlib.pyplot as plt
- 넘파이에서 npy 파일을 로드하는 방법?
- load() 메서드에 파일 이름을 전달한다.
In [3]:
fruits = np.load('fruits_300.npy')
In [4]:
print(fruits.shape)
첫 번쨰 차원은 샘플의 개수, 두번째 차원은 이미지 높이, 세 번째 차원은 이미지 너비이다.
아래는 첫 번째 이미지의 첫 번째 행을 출력한 것이다.
In [5]:
print(fruits[0, 0, :])
이 넘파이 배열은 흑백 사진을 담고 있으므로 0~255까지 정수값을 가진다.
- matplotlib의 imshow() 함수는 넘파이 배열로 저장된 이미지를 그려준다.
- 흑백 이미지이므로 cmap 매개변수를 'gray'로 지정한다.
In [6]:
plt.imshow(fruits[0], cmap='gray')
plt.show()
- 이미지에서 알 수 있듯 첫번째 행은 대부분 검은색이다가 일부만 하얀색이다.
- 넘파이 배열에서 0에 가까울수록 검게 나타내고 높은 값은 밝게 나타낸다.
- 따라서 앞서 출력한 첫번째 행의 데이터가 대부분 1이다가 특정 부분에서만 높은 숫자가 나오는 것이다.
- 보통 흑백 사진은 배경이 밝고 물체가 어두운데 이 흑백 이미지는 사진으로 찍은 이미지를 넘파이 배열로 변환할 때 반전시킨 것이다.
- 이렇게 바꾼 이유는 우리의 관심 대상이 바탕이 아니라 사과이기 때문이다.
cmap 매개변수를 'gray_r'로 지정하면 다시 반전하여 우리 눈에 보기 좋게 출력한다.
In [7]:
plt.imshow(fruits[0], cmap='gray_r')
plt.show()
이 데이터는 사과, 바나나, 파인애플이 각각 100개씩 들어있다. 바나나와 파인애플 이미지도 출력해보자.
In [8]:
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의 subplot() 함수를 사용하면 여러 개의 그래프를 배열처럼 쌓을 수 있다.
- 여기에서는 subplot(1,2)처럼 하나의 행과 2개의 열을 지정했다.
- 변환된 axs는 2개의 서브 그래프를 담고 있는 배열이다.
- axs[0]에 파인애플 이미지를, axs[1]에 바나나 이미지를 그렸다.
픽셀값 분석하기¶
- 사용하기 쉽게 fruits 데이터를 사과, 파인애플, 바나나로 각각 나누어보자.
- 넘파이 배열을 나눌 때 100 * 100 이미지를 펼쳐서 길이가 10,000인 1차원 배열로 만든다.
- 이렇게 펼치면 이미지로 출력하긴 어렵지만 배열을 계산할 때는 편하다.
- fruits 배열에서 순서대로 100개씩 선택하기 위해 슬라이싱 연산자를 사용한다.
- 그 다음 reshape() 메서드를 사용해 두 번째 차원(100)과 세 번째 차원(100)을 10,000으로 합친다.
- 첫 번째 차원을 -1로 지정하면 자동으로 남은 차원을 할당한다.
- 여기서는 첫 번째 차원이 샘플의 개수이다.
In [9]:
apple = fruits[0:100].reshape(-1, 100*100)
pineapple = fruits[100:200].reshape(-1, 100*100)
banana = fruits[200:300].reshape(-1, 100*100)
In [10]:
print(apple.shape)
길이 10,000짜리 1차원 배열이 100개가 되었음을 볼 수 있다.
- 이제 apple, pineapple, banana 배열에 들어 있는 샘플의 픽셀 평균값을 계산해보자.
- axis=1로 지정하면 열 방향의 평균값을 계산한다.
In [11]:
print(apple.mean(axis=1))
- 사과 샘플 100개에 대한 픽셀 평균값을 계산했다.
- 이를 히스토그램으로 그려 평균값 분포를 한눈에 살펴보자.
In [12]:
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()
- 사과, 파인애플, 바나나 세가지의 히스토그램을 겹쳐서 그렸다.
- alpha를 1보다 작게 설정해 조금 투명하게 보이도록 했다.
- 범례(legend)를 설정하여 어떤 과일에 대한 데이터인지 알도록 했다.
- 바나나는 구분하기 쉽지만 사과와 파인애플은 구분하기 힘들다.
- 더 좋은 구분법이 없을까?
- 샘플의 평균값이 아니라 픽셀별 평균값을 비교하면 더 명확할 것이다.
- 과일마다 형태가 다르기 때문이다.
In [13]:
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 크기 이미지로 바꿔서 출력하여 위 그래프와 비교해보자.
In [14]:
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()
평균값과 가까운 사진 고르기¶
In [15]:
abs_diff = np.abs(fruits - apple_mean)
abs_mean = np.mean(abs_diff, axis=(1,2))
print(abs_mean.shape)
- 이 중에서 값이 작은 순서대로 100개를 출력해보자.
- argsort() 함수는 작은 것부터 큰 순서대로 나열한 abs_mean 배열의 인덱스를 반환한다.
In [16]:
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()
- subplot() 함수로 10*10 = 100개의 서브 그래프를 만든다.
- 그래프가 많기 때문에 전체 그래프의 크기를 figsize=(10,10)으로 조금 크게 지정했다.
- 2중 for 반복문을 순회하면서 10개의 행과 열에 이미지를 출력한다.
- axs는 (10, 10) 크기의 2차원 배열이므로 i, j 두 첨자를 사용하여 서브 그래프 위치를 지정한다.
- 깔끔하게 이미지만 그리기 위해 axis('off')를 사용하여 좌표축을 그리지 않았다.
- 위와 같이 비슷한 샘플끼리 그룹으로 모으는 작업을 군집(clustering)이라고 한다.
- 클러스터링은 대표적인 비지도 학습 중 하나이다.
- 클러스터링으로 만든 그룹을 클러스터(cluster)라고 한다.
확인 문제¶
In [17]:
abs_diff2 = np.abs(fruits - banana_mean)
abs_mean2 = np.mean(abs_diff2, axis=(1,2))
print(abs_mean2.shape)
In [18]:
banana_index = np.argsort(abs_mean2)[: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[banana_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off')
plt.show()
- 사과의 예시와는 달리 바나나는 100장을 모두 골라내지 못했다.
In [19]:
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:90% !important; }</style>"))
'혼자 공부하는 머신러닝 + 딥러닝' 카테고리의 다른 글
[혼공머신] 14. PCA (Principal Component Analysis) (0) | 2021.12.18 |
---|---|
[혼공머신] 13. K-Means Clustering (0) | 2021.12.18 |
[혼공머신] 11. Ensemble Learning (0) | 2021.12.18 |
[혼공머신] 10. Cross Validation & Grid Search (0) | 2021.12.18 |
[혼공머신] 9. Decision Tree (0) | 2021.12.18 |