2 minute read

군집 알고리즘

비지도 학습

타깃을 모르는 사진을 종류별로 분류하는 것처럼 타깃이 없을 때 사용하는 머신러닝 알고리즘으로 특성데이터만 가지고 있을 때 사용한다.

과일 데이터

과일 데이터 링크 캐글 원본 링크

사과 바나나 파인애플이 있는 흑백 사진

넘파이 기본 저장 포멧인 npy 파일로 저장되어 있다

이미지 파일 분석

이미지 파일을 살펴보면

print(fruits.shape)
#(300, 100, 100)

100x100의 이미지가 300개가 있다는 것을 알 수 있다.

한 개의 사과 이미지를 imshow를 통해 확인할 수 있다.

plt.imshow(fruits[0], cmap='gray')
# 흑백이미지 이므로 gray
plt.show()

image-20220516201841644

#첫 번째 샘플
print(fruits[0, 0, :])
# 첫번째 샘플의 첫번째 행만
# 1개 샘플에 100 x 100이기 때문에

image-20220517202544366

흑백이미지는 0~255까지 값으로 되어 있는데 255에 가까울수록 흰색 값이다.

보기 편하게 cmap=’gray_r 로 지정하면 흑백이 reverse된다.

plt.imshow(fruits[0], cmap='gray_r')
# gray_r을 통해 반전할 수 있다.
plt.show()

image-20220517203329653

픽셀 값 분석하기

각 픽셀 값을 분석하기 위해서 차원을 합쳐준다.

2차원 배열을 펼쳐서 1차원 배열로 만들어준다. 행에는 샘플이 있고 열에는 픽셀이 있게 된다.

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

axis 방향

axis를 잘 지정해주어서 평균을 낸다.

axis=0으로 하면 행을 따라서 평균을 내고 axis=1으로 하면 열을 따라서 평균을 낸다.

모든 과일 샘플에 대해서 평균을 내야 하기 때문에 axis=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', 'pineapple', 'banana'])
plt.show()

image-20220517204837006

과일 중에서 바나나는 평균값이 20~60에 대부분이 분포해있어서 쉽게 구분할 수 있지만 파인애플과 사과를 구분하는 것은 쉽지 않을 것처럼 보인다.

샘플별 평균값이 아닌 픽셀 별 평균값을 구해 보면

#100개씩 과일별로 샘플을 나눈 후에 픽셀별 평균 내기
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()

image-20220518203720648

사과는 아래쪽 부분이 조금 더 두드러지고 파인애플은 전체적으로 고른 편이다 바나나는 중간 부분이 두드러지게 나타난다.

이 평균값들을 이미지로 나타내면

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') # 사과 100개의 평균 이미지 
axs[1].imshow(pineapple_mean, cmap='gray_r') # 파인애플 100개의 평균 이미지 
axs[2].imshow(banana_mean, cmap='gray_r') # 바나나 100개의 평균 이미지 
plt.show()

image-20220519200104247

이 평균 이미지로 사진을 고를 수 있는지

abs_diff = np.abs(fruits - apple_mean) # 각 데이터와 평균의 차이 구함 (abs:절대값)
abs_mean = np.mean(abs_diff, axis=(1,2)) # 이미지 부분 가로/세로모두의 평균을 구해야 하기 때문에 axis=1,2로 지정 첫번째 차원는 각 이미지를 나누는것이기 때문에 평균을 내지 않음
#300개의 1차원 배열이 나오게 된다. (총 샘플의 개수가 300개이므로)
print(abs_mean.shape)
# (300,)

#가장 작은 값을 찾기 위해 argsort를 사용
#argsort(abs_mean) : abs_mean를 sorting한 후 가장 작은 index를 반환
apple_index = np.argsort(abs_mean)[:100]

# 100개의 사과 이미지를 보기 위해 10x10 subplot을 사용하여 각 위치에 imshow를 사용한다
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()

사과 데이터의 평균과 가장 작은 100개의 데이터를 살펴보면 사과 100개 모두 잘 선별된 것을 볼 수 있다.

image-20220519212748407

하지만 똑같은 방법으로 바나나와 파인애플을 분류해보면

image-20220519214743947

image-20220519214800157

바나나는 두 개 파인애플 은 세 개의 사과 데이터가 섞여버린 것을 확인할 수 있다.

저 사과 데이터가 나머지 바나나/파인애플 평균값에 더 가깝기 때문에 잘못된 분류가 발생했을 것이다.

이렇게 비슷한 셈플끼리 그룹으로 묶는 것을 군집이라 하고 군집 알고리즘에서 만든 그룹을 클러스터(Cluster)라고 한다.

위의 데이터는 차례대로 사과 파인애플 바나나로 정렬되어있는 데이터여서 타깃을 전부 아는 상태였지만 실제로는 타깃이 없는 사진 데이터를 사용하게 될 것이다.

참고

박해선,혼자 공부하는 머신러닝, 한빛미디어, 2021,286~301p