본문 바로가기

AI/기계학습(Machine Learning)

[기계학습/ML]13. 비지도학습 - 군집(Clustering)

728x90
반응형

Pupbani가 다니는 회사인 물꼬기는 이번에 새로운 비즈니스 진출을 하기로 결정했다.

그것은 바로 농산물 판매 마켓이였다. 

마케팅 팀은 개업 기념으로 새로운 이벤트를 기획하고 있는데 내용은 다음과 같다.

  • 고객이 마켓에서 사고 싶은 과일 사진을 보내면 그 중 가장 많은 요청을 받은 과일 판매하려고 한다.
  • 1위로 선정된 과일 사진을 보낸 고객 중 몇명을 뽑아 당첨자로 선정할 것 이다.

마케팅 팀 박팀장은 Pupbani에게 고객이 보낸 사진들을 분류하는 머신러닝을 만들어달라고 요청했다.

Pupbani는 이 문제를 어떻게 해결해야 할까 고민이 깊어졌다....

 

Target을 모르는 비지도 학습

타겟을 모를 때 데이터들을 종류별로 분류하는 머신러닝 알고리즘이 있다.

바로 "비지도 학습(Unsupervised Learning)"이라는 알고리즘이다.

Pupbani는 마케팅 팀에게서 300장을 사진을 받아 비지도학습 모델을 만들어 보려고 한다.

!wget https://bit.ly/fruits_300 -O fruits_300.npy

import numpy as np
fruits = np.load('fruits_300.npy')
print(fruits.shape) # fruits 데이터의 형태
print(fruits[0, 0, :]) # fruits 데이터 중 1개의 과일 데이터 출력

데이터의 형태가 x,y축 100개 씩 z 축으로 300개 만큼 있는 3차원의 형태이다. 

이렇게 불러온 데이터는 matplotlib 라이브러리를 사용하여 우리가 알아보기 쉽게 사진 처럼 표현할 수 있다.

import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2)
axs[0].imshow(fruits[0], cmap='gray') # 검은 배경
axs[1].imshow(fruits[0], cmap='gray_r') # 흰 배경
plt.show()

fruits_300 데이터는 총 3개의 과일 데이터가 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()

픽셀값 분석

이제 Pupbani는 이 데이터들을 픽셀값 별로 나눠서 분류하려고 한다.

먼저 배열 계산을 쉽게 하기 위해 100 x 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) # 바나나

print("사과 :",apple.shape)
print("파인애플 :",pineapple.shape)
print("바나나나 :",banana.shape)

이제 각 배열에 들어 있는 샘플의 픽셀 평균값을 계산한다.

넘파이의 mean() 메서드를 사용한다.

  • 인자인 axis는 계산 축을 지정한다.
    • 0일 때 - y축으로 계산
    • 1일 때 - x축으로 계산

각 샘플들(100개 씩)의 평균값에 대한 히스토그램을 그려 평균값 분포를 확인한다.

pyplot의 hist() 함수를 사용한다.

  • alpha 인자를 1보다 작게 주면 그래프의 투명도를 줄일 수 있다.
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(['사과', '파인애플', '바나나나'])
plt.show()

히스토그램을 보면 바나나 사진의 평균값은 40 아래 집중되어 있다.

사과와 파인애플을 90 ~ 100사이에 모여 있다.

바나나는 확실하게 분류가 가능하지만 사과와 파인애플을 분류하는 것은 쉽지가 않다.

 

Pupbani는 샘플의 평균값이 아니라 픽셀별 평균값을 비교해보기로 했다.

픽셀의 평균은 mean()의 axis의 값을 1대신 0으로 지정하면 된다.

이번에는 pyplot의 bar() 함수를 사용하여 막대그래프로 그려보기로 했다.

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 x 100 크기로 바꿔서 이미지 처럼 출력해보았다.

픽셀을 평균 낸 이미지를 모두 합쳐서 놓은 대표 이미지라고 생각하면 된다.

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

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

이제 Pupbani는 과일별로 평균에 가장 가까운 사진을 골라보기로 했다.

절댓값 오차를 사용한다.

  • fruits 배열에 있는 모든 샘플에서 해당 과일의 평균 값을 뺀 절댓값의 평균을 계산하면 된다.
# 각 과일들의 픽셀값에 대한 평균들
means = [apple_mean,pineapple_mean,banana_mean]

# fruits 배열에서 각 과일들의 평균을 뺀 절댓값
abs_diffs = [np.abs(fruits - i) for i in means]

# 위에서 구한 절댓값의 평균
abs_means = [np.mean(i,axis=(1,2)) for i in abs_diffs]

# argsort를 사용해 각 과일의 픽셀값에 대한 평균값과의 오차가 가장 작은 샘플 100개씩 찾아 그 index를 저장
index_ = [np.argsort(abs_means[0])[:100],np.argsort(abs_means[1])[0:100],np.argsort(abs_means[2])[0:100]]

# 그림을 그리는 함수
def makePlot(index):
    fig,axs = plt.subplots(10,10,figsize=(10,10))
    for i in range(10):
        for j in range(10):
            axs[i, j].imshow(fruits[index[i*10 + j]], cmap='gray_r')
            axs[i, j].axis('off')
    plt.show()

# 출력
for i in index_:
	makePlot(i)
	print("")

이렇게 비슷한 샘플끼리 그룹으로 모으는 작업을 군집(Clustering)이라고 부르며 이렇게 만든 그룹을 클러스터(Cluster) 라고 부른다.

Pupbani는 이미 샘플의 종류를 알고 있어서 평균값을 계산해 분류를 할 수 있었다.

하지만 실제 비지도 학습에서는 샘플의 종류를 알지 못하기 때문에 미리 평균값을 구하지 못한다.

샘플의 종류를 알지 못하면서 어떻게 세 과일의 평균값을 찾을 수 있을까? 

Pupbani는 고민에 빠졌다...

728x90
반응형