--17.비지도 학습.ipynb--
Unsupervised Learning
target값 (레이블) 없는 머신러닝 알고리즘
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
base_path = r'/content/drive/MyDrive/dataset'
file_path = os.path.join(base_path, 'fruits_300.npy')
fruits = np.load(file_path)
fruits.shape
fruits[0]
fruits[0,0,:]
plt.imshow(fruits[0], cmap='gray')
plt.show()
"""
일반적으로 머신러닝에 학습하는 이미지는 반전된 형태.
배경이 검정색(0)에 가깝고 물체가 흰색(255)에 가까운 반전된 형태.
왜?
=> 관심대상이 바탕이 아니라 물체(사과)이기 때문.
'알고리즘' 수많은 덧셈, 곱셈 연산한다. 픽셀값이 0이면 출력도 0이되어 의미 상실됨.
관심대상인 물체에 높은 픽셀값을 부여하여 의미있는 값을 도출하기 위함.
"""
None
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')
plt.show()
apple = fruits[0:100].reshape(-1, 100100)
pineapple = fruits[100:200].reshape(-1, 100100)
banana = fruits[200:300].reshape(-1, 100*100)
apple.shape
apple.mean(axis=1) # 100개의 사과 이미지의 픽셀 평균값들
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 사이에 많이 모여있네요.
이 그림을 보면 바나나는 픽셀 평균값만으로 사과나 파인애플과 확실히 구분됩니다.
바나나는 사진에서 차지하는 영역이 작기 때문에 평균값이 작습니다.
반면, 사과와 파인애플은 많이 겹쳐 있어서 픽셀 값많으로는 구분하기 쉽지 않습니다.
사과나 파인애플은 대체로 형태가 동그랗고 사진에서 차지하는 크기도 비슷하기 때문입니다.
"""
None
np.mean(apple, axis=0)
np.mean(apple, axis=0).shape
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()
apple_mean
abs_diff = np.abs(fruits - apple_mean)
abs_diff.shape
abs_mean = np.mean(abs_diff, axis=(1,2))
abs_mean.shape # abs_mean 는 각 샘플의 오차평균
abs_mean
np.argsort(abs_mean) # 오름차순으로 나열한 abs_mean 배열의 '인덱스'를 리턴한다!!
apple_index = np.argsort(abs_mean)[:100]
apple_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[apple_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off') # axis('off') 좌표축 제거. (사진만 보겠다.)
plt.show()
"""
비슷한 샘플끼리 그룹으로 모으는 작업을 '군집 Clustering'이라 합니다.
'군집'은 대표적인 '비지도 학습' 중 하나.
군집 알고리즘에서 만든 그룹을 '클러스터 (cluster)' 라고 한다.
"""
None
"""
하지만! 우리는 이미 사과, 파인애플, 바나나 가 있다는 것을 알고 있었습니다.
즉 타겟 갓을 알고 있었기 때문에 사과, 파인애플, 바나나의 평균값을 계산해서 가장 가까운 과일을
찾을 수 있었습니다.
실제 비지도 학습에서는 타겟 값을 모르기 때문에 이처럼 이처럼 샘플의 평균값을 미리 구할 수 없습니다.
타깃값을 모르면서 어떻게 세 과일의 평균값을 찾을 수 있을까요?
"""
None
fruits_2d = fruits.reshape(-1, 100 * 100)
fruits_2d.shape
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_2d) # 비지도 학습 이므로 fit()에 target데이터를 사용하지 않는다.
km.labels_
np.unique(km.labels_, return_counts=True)
def draw_fruits(arr, ratio=1) :
n = len(arr) # n: 샘플개수
rows = int(np.ceil(n/10))
cols = n if rows < 2 else 10
fig, axs = plt.subplots(rows, cols,
figsize=(colsratio, rowsratio),
squeeze=False # subplot 결과가 2차원으로 나올텐데 이것을 (2, )로 바꿔버린다. False는 차원압축 하지 않겠다는 뜻.
)
for i in range(rows) :
for j in range(cols) :
if i 10 + j < n :
axs[i, j].imshow(arr[i10 + j], cmap='gray_r')
axs[i, j].axis('off')
plt.show()
fruits[km.labels_ == 0]
drawfruits(fruits[km.labels == 0])
drawfruits(fruits[km.labels==1])
drawfruits(fruits[km.labels==2])
km.clustercenters
km.clustercenters.shape
drawfruits(km.cluster_centers.reshape(-1, 100, 100),ratio=3)
fruits_2d[100].shape
km.transform(fruits_2d[100:101])
"""
↑ 하나의 샘플을 전달했기 때문에 리턴된 배열은 크기가 (1, 클러스터 개수)인 2차원 배열이다.
첫번째가 레이블0, 두번째가 레이블1 .....
첫번째 클러스터까지의 거리가 3393.8로 가장 작다. 이 샘플(100번째)는 레이블 0에 속한 것 같다.
"""
None
km.predict(fruits_2d[100:101])
draw_fruits(fruits[100:101])
km.niter
"""
n_cluster=3 으로 지정했다? <- 이미 타겟에 대한 정보를 활용한 셈이다.
실전의 데이터는 이러한 정보도 없을것이다.
과연 최적의 클러스터 개수는 어떻게 지정할 것인가?
"""
None
"""
사실 군집 알고리즘에서 적절한 k 값을 찾기위한 완벽한 방법은 없다.
다양한 방법은 있지만, 장단점들이 있다.
대표적인 방법인 엘보우(elbow) 방법을 소개합니다.
"""
None

inertia = []
for k in range(2, 7) : # 클러스터 개수를 2~6까지 바꿔가며 5번 훈련
km = KMeans(nclusters=k, random_state=42)
km.fit(fruits_2d)
inertia.append(km.inertia)
plt.plot(range(2,7), inertia)
plt.xlabel('k')
plt.ylabel('inertia')
plt.show()