머신러닝

머신 러닝(with Google Colab) - 6일차(1)

aisw7984 2024. 10. 21. 15:26
반응형

비지도 학습

앞서 머신러닝의 학습은 지도와 비지도 학습이 있다고 했었는데 이제 비지도 학습에 대해 알아보자. 지도학습과의 차이점은 쉽게 타깃에 대한 사전 데이터가 없다는 점이다. 따라서 알고리즘이 스스로 데이터를 판단해서 예측해야 한다. 과일의 데이터를 이용하여 비지도 학습에 대해 알아보자


데이터의 준비하는데 이번에는 사이트의 데이터를 불러와 저장해서 사용해 보자 구글 코랩에서는 '!'를 입력하면 명령프롬포트창(cmd)과 같이 사용이 가능하다. 이를 사용하여 데이터를 불러와 확인해 보자.

!wget http://bit.ly/fruits_300 -O fruits_300.npy
import numpy as np
import matplotlib.pyplot as plt
fruits = np.load('fruits_300.npy')
print(fruits.shape)
->  (300, 100, 100)

fruits 데이터는 여러 과일의 이미지가 흑백으로 저장된 데이터 이다. shape를 확인해 보면 300개의 100* 100 픽셀의 이미지라는 것을 알 수 있다. 한번 첫 번째 과일의 1번째 행에 데이터를 출력해 보자

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*100 이미지의 1번째 행이기 때문에 100개의 데이터가 나온 걸 볼 수 있는데 앞서 이미지가 흑백이미지라고 했는데 흑백의 경우 0~255의 값으로 색상을 정하게 된다. 0 에가까울수록 검은색이고 255에 가까울수록 흰색이다. 그럼 이미지를 출력해 보자 이미지의 경우 imshow() 함수를 통해 넘파이 배열로 지정된 이미지를 그릴 수 있고 안의 매개변수 cmap은 색상을 정하는 것인데 앞서 흑백의 이미 지기 때문에 gray를 사용해 준다. 추가적으로 gray_r을 사용한다면 흰색 백색이 반전되어 배경이 하얀색에 피사체가 검은색 계연인 이미지를 볼 수 있다.

plt.imshow(fruits[200], cmap = "gray")
fruits[0,60, :]

과일의 200번째 데이터는 바나나가 출력되는 걸 알 수 있고 나머지 300개의 데이터에도 이와같은 흑백의 이미지가 있다는 것을 알 수 있다. 다른 이미지도 한번 불러와 보자 matplotlib에서 여러 개의 이미지를 불러오고 싶을 때는 subplots을 사용한다. subplots에는 몇 행 몇 열로 설정할지 정하고 접근할 때는 axs를 통해 어느 위치에 값을 넣을 것인지 정할 수 있다.

fig, axs = plt.subplots(1,2)
axs[0].imshow(fruits[000], cmap ="gray_r")
axs[1].imshow(fruits[100], cmap ="gray_r")

 

대충 100개의 단위로 과일이 구분됨을 볼 수 있다.

 


우리가 과일을 구분하기 위해서 생각해 볼 수 있는 방법은 픽셀 단위로 데이터를 분석하는 것인데. 하나의 이미지에 대한 픽셀의 평균을 이용해서 분석을 해보자. 우선 필요한 작업이 100*100의 2차원 배열인 이미지를 1차원 배열로 바꿔주는 것이다. 이는 앞서 배운 reshape를 이용하면 쉽게 사용할 수 있다. 

reshape를 통해 1차원으로 바꾼 데이터는 길이가 10000인 1차원 배열인데 이제 각각의 샘플에 대해 평균을 내기 위해서는 배열의 값을 열로 접근해서 평균값을 계산해야 한다. 따라서 axis=1을 사용하면 열에 대한 값이고 평균값은 넘파이에서 제공하는 mean을 사용하면 된다.

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.mean(axis=1))
print(pineapple.mean(axis=1))
print(banana.mean(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개의 픽셀에 대한 평균값이 나오고 다른 과일들도 이와 비슷한 형태로 나왔을 것이다. 이제 이를 히스토그램으로 확인해 보자.

#히스토그램
import matplotlib.pyplot as plt
# 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(["apple", "pinapple", "banana"])
plt.show()

#샘플의 픽셀 평균값으로 비교하기에는 사과와 파인애플이 구분이 잘안됨

결과를 보면 바나나의 경우 확실히 구분이 되지만 사과와 파인애플은 잘 구분이 되지 않는다. 이는 하나의 과일 샘플의 평균을 내서 비교를 했기 때문에 형태가 비슷한 사과와 파인애플은 겹칠 수밖에 없다. 

생각보다 해결하는 방법은 간단한데 평균을 열이 아닌 행으로 즉 axis = 0올 하면 된다, 이렇게 한다면 과일의 이미지의 각 픽셀들의 평균을 낼 수 있고 평균된 값을 이미지로 출력한다면 과일들의 평균 이미지를 확인할 수 있다.

#픽셀의 평균값을 이미지 형태로 출력
#각 항목의 픽셀 평균값을 구하고 이미지형태(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 = (10,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()

이제 각 과일들의 평균을 알아냈다면 평균을 과일 중 사과를 예측해 보자 일단 평균의 shape에 대해 알아보면

print(apple_mean.shape) => (100,100)

우리가 가지고 있는 과일의 데이터는 (300,100,100)이기 때문에 과일의 데이터에 평균을 빼주게 되면 각 과일 데이터별 오차에 대해 구할 수 있다. 두 데이터의 차원이 다르지만 넘파이 배열간의 빼기에서는 300의 과일 중 하나의 데이터는 똑같은 (100*100)이므로 각 데이터별로 평균을 빼주게 되는 결과가 된다.

abs_diff = np.abs(fruits -apple_mean)
print(abs_diff.shape) => (300,100,100)
abs_mean = np.mean(abs_diff, axis = (1,2))
print(abs_mean.shape) = > (300,)

위의 코드는 1차원 2차원의 평균값을 3차원의 개수인 300개로 만들어 주기 위해서 사용했다.

만약 이미지가 사과의 평균과 비슷하면 오차가 적을 것이다. 따라서 오차를 오름차순으로 배열하여 인덱스에 저장해 주고 10X 10의 플롯을 만들어 각 플롯에 이미지를 넣어주는 코드를 작성해 출력해 보자. 

#argsort 는 오름차 순으로 인덱스를 재배열하는것
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")
    axs[i,j].axis("off") # 열 바꿈
plt.show()​

결과는 매우 성공적으로 오차를 통해 과일을 예측해 냈다. 이를 범위를 바꿔서 해보면 파인애플과 바나나도 동일한결과를 얻을 수 있다. 이렇게 비슷한 데이터가 뭉쳐져 있는 것을 클러스터(군집)이라고 하고 이 군집을 이용하는 방법은 다음에 이어서 하자

반응형