[ML Study]ch06-1 군집 알고리즘
혼자 공부하는 머신러닝+딥러닝 [6-1]
본 포스팅 한빛미디어의 <혼자공부하는 머신러닝+딥러닝(박해선 저)>를 요약 정리했습니다.
1. 비지도 학습
타깃이 없을 때 사용하는 머신러닝 알고리즘을 비지도 학습이라고 한다.
타깃(사진에 대한 정답)을 모르는 사진들을 종류별로 분류하려 한다.
이를 위해 사진의 픽셀값을 모두 평균내서 비슷한 과일을 모아보는 방법을 제안한다.
2. 과일 사진 데이터 준비하기
npy파일로 저장된 사과, 바나나, 파인애플을 담고 있는 흑백사진 데이터를 준비한다.
npy파일을 다운로드 해야한다.
[과일 데이터셋의 출처] https://www.kaggle.com/moltean/fruits
wget 오류가 떠서 https://bit.ly/fruits_300_data에 접속해 fruits_300.npy파일을 다운 받은 후,
주피터랩에 따로 파일을 넣어주고 실행시켰다.
이 배열은 첫 번째 차원을 300으로 샘플의 개수, 두 번째 차원과 세 번째 차원은 둘 다 100으로 각각 이미지 높이, 이미지 너비를 나타낸다.
이미지의 크기는 100x100으로 300개의 샘플이 있는 것이다.
첫 번째 이미지의 첫 번째 행을 모두 선택하여 픽셀 100개에 들어 있는 값을 출력해 본다.
print(fruits[0, 0, :])
imshow() 함수를 사용해 출력된 값을 이미지로 그려본다. (이미지 : 사과)
이때, 흑백 이미지이므로 cmap 매개변수를 사용해 gray로 지정해 주는데 이를 또 반전시켜주어야 한다.
0~255까지의 정숫값을 가지는 넘파이 배열은 0에 가까울 수록 검게 나타나고 높은 값은 밝게 표시가 된다.
이대로 출력한다면 배경은 검게 중간 부분은 밝게 나타나게 된다.
사실 우리가 사용하는 흑백 이미지는 찍은 사진을 넘파이 배열로 변환할 때 반전시켜 실제 사과가 가지는 낮은 값을 밝은 색인 높은 값으로 바꾼 것이다. (지금까지의 출력 결과)
그렇게 되면 컴퓨터가 바탕에 집중하게 되는 것을 막고 높은 값을 가진 사과에 집중하게 된다.
픽셀값이 높을수록 출력값이 커지는 것에 의미를 부여할 수 있으므로 255에 가까운 값에 집중하게 되는 것이다.
그러나 0에 가까울 수록 검게 나타나고 높은 값은 밝게 표시가 되므로 보기 안좋다.
따라서 또 반전시켜주어 배경이 아니라 사과가 흑백인 이미지를 나타내도록 한다. (gray_r 사용)
이제는 0에 가까울 수록 밝게 나타나고 높은 값은 검게 나타난다.
plt.imshow(fruits[0], cmap='gray_r')
plt.show()
데이터에 100개씩 들어있는 바나나와 파인애플 이미지도 같은 방식으로 출력해 본다.
fig, axs = plt.subplots(1, 2)
axs[0].imshow(fruits[100], cmap='gray_r')
axs[1].imshow(fruits[200], cmap='gray_r')
plt.show()
여러 개의 그래프를 나타내기 위해 subplots(1,2)로 행과 열을 지정해주었고,
axs[0], axs[1] 배열로 각각 파인애플, 바나나 이미지를 담아 출력한다.
3. 픽셀값 분석하기
fruits 데이터를 사과, 파인애플, 바나나로 각각 나누어 보자.
두 번째 차원과 세 번째 차원{(100, 100)_2차원 배열}을 1차원 배열로 나열해 분리한다.
100x100으로 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)이다.
픽셀 평균값을 계산하기 위해 mean() 메서드를 사용할 것이다. axis로 평균을 계산할 축을 지정한다.
axis=0은 행, axis=1은 열을 축으로 한다.
즉, (100, 10000) 배열에서 axis=0(100_첫 번째 축_행), axis=1(10,000_두 번째 축_열)이 되는 것이다.
위에서 계산할 때 가로로 10,000을 만들었으니 axis=1을 지정해 평균을 계산한다.
print(apple.mean(axis=1))
히스토그램을 그려 평균값의 분포를 확인해 보자.
alpha 값을 조정해 투명도를 줄여 겹쳐 그려보고, 알기 쉽게 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'])
plt.show()
픽셀값으로만 구분하기 쉽지 않으므로 샘플의 평균값이 아닌 픽셀별 평균값을 비교해 본다.
axis=0(100_첫 번째 축_행)을 사용해 전체 샘플에 대한 10,000개의 픽셀별 평균값을 구해본다.
사과, 파인애플, 바나나에 대한 막대그래프이다.
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()
이제 픽셀을 평균 낸 이미지를 모든 사진을 합쳐 놓은 대표 이미지로 생각할 수 있다.
픽셀 위치에 따라 값의 크기가 차이나므로 세 과일을 구분할 수 있다.
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()
4. 평균값과 가까운 사진 고르기
사과 사진의 평균값(apple_mean)과 가장 가까운 사진을 고르기 위해, 넘파이 abs() 함수를 이용한 절대값으로 평균을 계산한다.
abs_diff = np.abs(fruits - apple_mean) # abs_diff 배열 : (300, 100, 100)
abs_mean = np.mean(abs_diff, axis=(1,2)) # 각 샘플에 대한 평균 구하기
print(abs_mean.shape) # abs_mean : 1차원 배열 (300, )
apple_mean과 오차가 가장 작은 샘플 100개를 고르기 위해서
np.argsort() 함수로 작은 것에서 큰 순서대로 나열하여 처음 100개를 선택하고 10x10 격자로 그래프를 그려본다.
apple_index = np.argsort(abs_mean)[:100]
fig, axs = plt.subplots(10, 10, figsize=(10, 10)) # 100개의 서브 그래프
for i in range(10): # 이중 for문으로 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()
모두 사과가 나왔으므로 세 과일을 구분할 수 있게 되었다.
비슷한 샘플끼리 그룹으로 모으는 작업을 군집이라 하고 이는 대표적인 비지도 학습 작업 중 하나이다.
군집 알고리즘에서 만든 그룹을 클러스터라고 부른다.