촉촉한초코칩
[혼공머신] Ch06 본문
https://colab.research.google.com/drive/1sfIIY16vBHCjrX5VPn4HrCZR5UYLzgpy#scrollTo=D4p969zjRt35
Ch06. 비지도 학습
비슷한 과일끼리 모으자!
- 타깃이 없는 데이터를 사용하는 비지도 학습과 대표적인 알고리즘을 배운다.
- 대표적인 군집 알고리즘인 k-평균을 배운다.
- 대표적인 차원 축소 알고리즘인 주성분 분석(PCA)를 배운다.
06-1 군집 알고리즘
흑백 사진을 분류하기 위해 여러 가지 아이디어를 내면서 비지도 학습과 군집 알고리즘을 이해한다.
문제 : 타깃을 모르는 사진을 종류별로 분류하기
비지도 학습 (Unsupervised Learning)
- 타깃이 없을 때 사용하는 머신러닝 알고리즘
픽셀값을 이용해서 사진을 분류한다.
#과일 사진 데이터 준비하기
!wget https://bit.ly/fruits_300_data -o fruits_300.npy
import numpy as np
import matplotlib.pyplot as plt
#fruits : 넘파일 배열이며 fruits_300.npy 파일에 들어 있는 모든 데이터를 담고 있다.
#wget 실행 후 생성되는 data파일에 데이터가 담겨져 있디.
fruits = np.load('/content/fruits_300_data')
print(fruits.shape) #(300, 100, 100) -> 샘플 개수, 이미지 높이, 이미지 너비
#첫번째 이미지의 첫번째 행 출력하기
#마지막 인덱스는 지정하지 않거나 슬라이싱 연산자를 쓰면 첫번째 이미지의 첫번째 행을 모두 선택할 수 있다.
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]
#첫번째 이미지를 그림으로 그려서 숫자와 비교해본다.
plt.imshow(fruits[0], cmap='gray')
plt.show()
* 넘파일 배열은 흑백 사진을 담고 있다.
사진으로 찍은 이미지를 넘파일 배열로 변환할 때 반전시켰기 때문에 흰 바탕(높은 값)은 검은색(낮은 값)으로 만들고 짙은 부분(낮은 값)은 밝은색(높은 값)으로 바뀐다. 우리가 보는 것과 컴퓨터가 처리하는 방식이 다르기 때문
0에 가까울수록 검게 나타나고 높은 값은 밝게 표시된다.
cmap 매개변수를 gray_r로 지정하면 다시 우리가 보는 것과 동일한 이미지가 출력된다.
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(행, 열) : 여러 개의 그래프를 배열처럼 쌓을 수 있도록 한다.
* axs : 2개의 서브 그래프를 담고 있는 배열
픽셀값 분석하기
- fruits 데이터를 사과, 파인애플, 바나나로 나눈다.
넘파일 배열을 나눌 때 2차원 배열인 100x100 이미지를 펼쳐서 길이가 10,000인 1차원 배열로 만든다.
→ 이미지로 출력하긴 어렵지만 배열을 계산할 때 편리하다.
#reshape() : 두번째 차원과 세번째 차원을 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)
- 샘플마다 픽셀의 평균값을 계산해야 하므로 mean()을 사용하여 평균을 계산할 축을 지정한다.
→ axis=0으로 하면 첫번째 축인 행을 따라 계산, 1로 지정하면 두번째 축인 열을 따라 계산
샘플을 모두 가로로 나열했으므로 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
# ...
# 81.9424 87.1687 97.2066 83.4712 95.9781 91.8096 98.4086 100.7823
# 101.556 100.7027 91.6098 88.8976]
#히스토그램으로 평균값 분포 보기
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
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*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()
→ 대표 이미지와 가까운 사진을 골라 내어 구분한다.
평균값과 가까운 사진 고르기
- fruits 배열에 있는 모든 샘플에서 과일_mean을 뺀 절댓값의 평균을 계산한다.
#abs_diff : 각 샘플에 대한 평균을 구하기 위해 axis에 두번째, 세번째 차원을 모두 지정한다.
#abs_mean : 각 샘플의 오차 평균으로, 크기가 (300,)인 1차원 배열이다.
abs_diff = np.abs(fruits - apple_mean)
abs_mean = np.mean(abs_diff, axis=(1,2))
print(abs_mean.shape) #(300,)
#값이 가장 작은 순서대로 100개 고르기 -> apple_mean과 오차가 가장 적은 샘플 100개 고르기
#np.argsort() : 작은 것에서 큰 순서대로 나열한 abs_mean 배열의 인덱스를 반환한다.
apple_index = np.argsort(abs_mean)[:100]
#subplots() : 10*10 = 100개의 서브 그래프 만들기
fig, axs = plt.subplots(10, 10, figsize=(10,10))
#axis : 10*10의 2차원 배열이므로 i, j를 사용하여 서브 그래프의 위치를 지정한다.
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()
* 군집 (Clustering) : 비슷한 샘플끼리 그룹으로 모으는 작업
* 클러스터 (Cluster) : 군집 알고리즘에서 만든 그룹
문제점 : 타깃값을 알고 있었기 때문에 사진 평균값을 계산해서 가장 가까운 과일을 찾을 수 있었지만 실제 비지도 학습에서는 타깃값을 모르기 때문에 샘플 평균값을 미리 구할 수 없다.
해결 방법 : k-평균 알고리즘 사용하기
정리 [비슷한 샘플끼리 모으기]
- 문제 : 고객들이 올린 과일 사진을 자동으로 모은다. 어떤 과일 사진을 올릴지 모르기 때문에 미리 예상할 수 없어 타깃값을 준비하여 분류 모델을 훈련하기 어렵다.
- 비지도 학습 : 타깃값이 없을 때 데이터에 있는 패턴을 찾거나 데이터 구조를 파악하는 머신러닝 방식 → 스스로 데이터가 어떻게 구성되어 있는지 분석한다.
- 대표적인 비지도 학습 문제 : 군집 → 비슷한 샘플끼리 모으는 작업
06-2 k-평균
k-평균 알고리즘 작동 방식을 이해하고 과일 사진을 자동으로 모으는 비지도 학습 모델을 만든다.
k-평균 군집 알고리즘 : 처음에는 랜덤하게 클러스터 중심을 선택하고 점차 가까운 샘플의 중심으로 이동한다.
k-평균 알고리즘의 작동 방식
- 무작위로 k개의 클러스터 중심을 정한다.
- 각 샘플에서 가장 가까운 클러스터 중심을 찾아 해당 클러스터의 샘플로 지정한다.
- 클러스터에 속한 샘플의 평균값으로 클러스터 중심을 변경한다.
- 클러스터 중심에 변화가 없을 때까지 2번으로 돌아가 반복한다.
KMeans 클래스 KMeans
- 비지도 학습이므로 fit() 메서드에서 타깃 데이터를 사용하지 않는다.
- 군집된 결과는 KMeans 클래스 객체의 labels_ 속성에 저장된다. labels_ 배열의 길이는 샘플 개수와 동일하며 배열은 각 샘플이 어떤 레이블에 해당되는지 나타낸다.
#3차원 배열(샘플개수, 너비, 높이)을 2차원 배열(샘플개수, 너비*높이)로 변경한다.
!wget https://bit.ly/fruits_300_data -o fruits_300.npy
import numpy as np
fruits = np.load('fruits_300_data')
fruits_2d = fruits.reshape(-1, 100*100)
#n_clusters 매개변수 : 클러스터 개수 지정
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_2d)
print(km.labels_)
#레이블 0,1,2로 모은 샘플 개수를 확인한다.
print(np.unique(km.labels_, return_counts=True))
#(array([0, 1, 2], dtype=int32), array([111, 98, 91])) -> array([]) 숫자는 각 레이블마다 몇 개의 샘플을 모았는지 나타낸다.
#각 클러스터가 어떤 이미지를 나타냈는지 그림으로 출력해본다.
import matplotlib.pyplot as plt
def draw_fruits(arr, ratio=1):
n = len(arr) #n : 샘플 개수
#한줄에 10개씩 이미지를 그린다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산한다.
rows = int(np.ceil(n/10))
#행이 1개이면 열의 개수는 샘플 개수이다.
cols = n if rows < 2 else 10
fig, axs = plt.subplots(rows, cols, figsize=(cols*ratio, rows*ratio), squeeze=False)
for i in range(rows):
for j in range(cols):
if i*10 + j < n:
axs[i, j].imshow(arr[i*10 + j], cmap='gray_r')
axs[i, j].axis('off')
plt.show()
draw_fruits(fruits[km.labels_==0])
draw_fruits()
- (샘플 개수, 너비, 높이) 3차원 배열을 입력받아 가로로 10개씩 이미지를 출력한다.
샘플 개수에 따라 행과 열의 개수를 계산하고 figsize를 지정한다. - 2중 for 반복문을 사용하여 첫번째 행을 따라 이미지를 그린다.
- 이 함수를 사용하여 레이블이 0인 과일 사진을 모두 그려본다.
km.labels_ == 0과 같이 쓰면 km.labels_ 배열에서 값이 0인 위치는 True, 그 외는 False가 된다.
레이블이 0으로 클러스터링된 91개의 이미지를 출력했다.
다른 두 클러스터도 출력해본다.
draw_fruits(fruits[km.labels_==1])
draw_fruits(fruits[km.labels_==2])
- 1은 바나나, 2는 사과로만 이루어져 있다.
- 하지만 0은 파인애플에 사과와 바나나가 섞여 있으므로 샘플을 완벽하게 구별해내지 못했다.
클러스터 중심
- cluster_centers_ 속성 : KMeans 클래스가 최종적으로 찾은 클러스터 중심이 저장되어 있다.
fruits_2d 샘플의 클러스터 중심이기 때문에 각 중심을 이미지로 출력하려면 100*100 크기의 2차원 배열로 바꿔야 한다.
draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3)
- transform() : 훈련 데이터 샘플에서 클러스터 중심까지 거리로 변환해주는 함수
#인덱스가 100인 샘플에 적용해본다.
print(km.transform(fruits_2d[100:101]))
#[[3393.8136117 8837.37750892 5267.70439881]] -> 하나의 샘플을 전달했기 때문에 반환된 배열 크기는 (1, 클러스터 개수)인 2차원 배열이다.
#첫번째 클러스터 (레이블0), 두번째 클러스터(레이블1)가 각각 첫번째 원소, 두번째 원소의 값이다.
#가장 가까운 클러스터 중심을 예측 클래스로 출력
print(km.predict(fruits_2d[100:101])) #[0] -> 파인애플
draw_fruits(fruits[100:101]) #파인애플이 나온다.
#알고리즘이 반복한 횟수 출력하기
print(km.n_iter_) #4
클러스터 중심을 사용해 데이터셋을 저차원으로 변환할 수 있다.
또는 가장 가까운 거리에 있는 클러스터 중심을 샘플의 예측 값으로 사용할 수 있다.
문제 : 타깃 정보를 알고 있었기 때문에 n_clusters를 3으로 지정했다. 클러스터 개수를 모를 때 최적의 클러스터 개수를 찾는 방법은?
최적의 k 찾기
- k-평균 알고리즘의 단점 : 클러스터 개수를 사전에 지정해야 함
- 적절한 클러스터 개수 찾는 방법 : 엘보우 (elbow) 방법
→ 클러스터 개수를 늘려가면서 이너셔의 변화를 관찰하여 최적의 클러스터 개수를 찾는다.
→ 이너셔를 그래프로 그리면 감소하는 속도가 꺾이는 지점이 있다. 이 지점부터는 클러스터 개수를 늘려도 클러스터에 잘 밀집된 정도가 크게 개선되지 않는다. (= 이너셔가 크게 줄어들지 않는다.) - 이너셔 (Inertia) : 클러스터 중심과 클러스터에 속한 샘플 사이의 거리의 제곱 합 → 클러스터에 속한 샘플이 얼마나 가깝게 모여 있는지 나타내는 값
- KMeans 클래스는 자동으로 이너셔를 계산해서 inertia_ 속성으로 제공한다.
클러스터 개수 k를 2~6까지 바꿔가며 KMeans 클래스를 5번 훈련한다.
fit() 메서드로 모델 훈련한 후 inertia_ 속성에 저장된 이너셔 값을 inertia 리스트에 추가한다.
마지막으로 inertia 리스트에 저장된 값을 그래프로 출력한다.
inertia = []
for k in range(2, 7):
km = KMeans(n_clusters=k, n_init='auto', 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()
- k=3에서 그래프의 기울기가 조금 바뀌었다.
- 엘보우 지점보다 클러스터 개수가 많아지면 이너셔의 변화가 줄어들면서 군집 효과도 줄어든다. (위 그래프에서는 지점이 명확하진 않다.)
정리 [과일을 자동으로 분류하기]
- 타깃값을 모를 때 자동으로 사진을 클러스터로 모을 수 있는 k-평균 알고리즘 사용 (KMeans 클래스)
- k-평균 알고리즘
- 처음에 랜덤하게 클러스터 중심을 정하고 클러스터를 만든다. 클러스터의 중심을 이동하고 다시 클러스터를 만드는 식으로 반복해서 최적의 클러스터를 구성한다.
transform() : 각 샘플에서 각 클러스터까지의 거리를 하나의 특성으로 활용
predict() : 새로운 샘플에 대해 가장 가까운 클러스터를 예측값으로 출력 - 클러스터 중심 : k-평균 알고리즘이 만든 클러스터에 속한 샘플의 특성 평균값
- 엘보우 방법 : 최적의 클러스터 개수를 정하는 방법 중 하나
클러스터 개수를 늘리면서 반복하여 KMeans 알고리즘을 훈련하고 이너셔가 줄어드는 속도가 꺾이는 지점을 최적의 클러스터 개수로 결정 - k-평균 알고리즘의 클러스터 중심까지 거리를 특성으로 사용할 수 있다.
장점 : 훈련 데이터의 차원을 크게 줄이고 데이터셋의 차원을 줄이면 지도 학습 알고리즘의 속도를 크게 높일 수 있다.
06-3 주성분 분석
차원 축소에 대해 이해하고 대표적인 차원 축소 알고리즘인 PCA(주성분 분석) 모델을 만든다.
문제 : 군집이나 분류에 영향을 끼치지 않으면서 업로도된 사진 용량 줄이기
차원과 차원 축소
- 차원 (Dimension) : 데이터가 가진 속성/특성 ≠ 배열의 차원과는 다르다.
- 차원 축소 (Dimensionality Reduction) : 데이터를 가장 잘 나타내는 일부 특성을 선택하여 데이터 크기를 줄이고 지도 학습모델 성능을 향상시킬 수 있는 방법 → 줄어든 차원에서 다시 원본 차원으로 손실을 최대한 줄이면서 복원할 수도 있다.
- 차원 축소 알고리즘 : 주성분 분석 (Principal component analysis, PCA)
주성분 분석(PCA) 소개
- 데이터에 있는 분산이 큰 방향을 찾는다.
* 분산 : 데이터가 널리 퍼져있는 정도
* 분산이 큰 방향 : 데이터를 잘 표현하는 어떤 벡터 → 이 벡터를 주성분이라고 한다. - 주성분 벡터의 원소 개수 = 원본 데이터셋에 있는 특성(차원) 개수 → 원본 데이터는 주성분을 사용해 차원을 줄일 수 있다.
- 주성분 = 원본 차원
주성분으로 바꾼 데이터 = 차원이 줄어듦
주성분에 투영하여 바꾼 데이터 = 원본이 가지고 있는 특성을 가장 잘 나타냄
PCA 클래스
- n_components 매개변수 : 주성분 개수 지정
- components_ 속성 : PCA 클래스가 찾은 주성분 저장
!wget https://bit.ly/fruits_300_data -o fruits_300.npy
import numpy as np
fruits = np.load('fruits_300_data')
fruits_2d = fruits.reshape(-1, 100*100)
from sklearn.decomposition import PCA
pca = PCA(n_components=50)
pca.fit(fruits_2d)
print(pca.components_.shape) #(50, 10000) -> (주성분 개수, 원본 데이터의 특성 개수)
#이미지처럼 출력
draw_fruits(pca.components_.reshape(-1,100,100))
원본 데이터를 주성분에 투영하여 특성의 개수를 50개로 줄인다.
- fruits_2d : 10000개의 특성을 가진 300개의 이미지
- fruits_pca : PCA 모델을 사용해서 만든 50개 특성을 가진 데이터
print(fruits_2d.shape) #(300, 10000)
fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape) #(300, 50)
문제 : 데이터 차원을 줄여도 다시 원상 복구 할 수 있을까?
원본 데이터 재구성
- inverse_transform() : 50개의 차원으로 축소한 데이터를 전달해 10000개의 특성 복원하기
fruits_inverse = pca.inverse_transform(fruits_pca)
print(fruits_inverse.shape) #(300, 10000)
- 복원된 데이터를 100*100 크기로 바꾸어 100개씩 나눠서 출력하기 (순서대로 사과, 파인애플, 바나나를 100개씩 담고 있다.)
fruits_reconstruct = fruits_inverse.reshape(-1, 100, 100)
for start in [0, 100, 200]:
draw_fruits(fruits_reconstruct[start:start+100])
print('\n')
→ 50개의 특성을 10000개로 늘려 과일이 잘 복원되었다.
설명된 분산 (Explained variance)
- 주성분이 원본 데이터의 분산을 얼마나 잘 나타내는지 기록한 값
- PCA 클래스의 explained_variance_ratio_ : 주성분의 설명된 분산 비율 기록 → 분산 비율을 모두 더하면 50개의 주성분으로 표현하고 있는 총 분산 비율을 얻을 수 있다.
print(np.sum(pca.explained_variance_ratio_)) #0.9215648934443857
- 분산 비율이 높다 = 복원이 잘 된다.
- 그래프로 그려보면 적절한 주성분의 개수를 찾는 데 도움이 된다.
plt.plot(pca.explained_variance_ratio_)
plt.show()
- 처음 10개의 주성분이 대부분의 분산을 표현하고 있다.
그다음부터는 각 주성분이 설명하고 있는 분산은 비교적 작다.
다른 알고리즘과 함께 사용하기
- PCA로 차원 축소된 데이터를 사용하여 지도 학습 모델을 훈련시킨다.
원본 데이터를 사용했을 때와 어떤 차이가 있는지 확인한다. → 로지스틱 회귀 모델 사용 - 지도 학습 모델은 타깃값이 필요하다. → 사과 0, 파인애플 1, 바나나 2로 지정
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
#파이썬 리스트와 정수를 곱하면 리스트 안의 원소를 정수만큼 반복한다. -> 각각 100개씩 저장되도록 한다.
target = np.array([0]*100 + [1]*100 + [2]*100)
#원본데이터(fruits_2d) 모델 돌려보기 + 교차 검증 수행
from sklearn.model_selection import cross_validate
scores = cross_validate(lr, fruits_2d, target)
print(np.mean(scores['test_score'])) #0.9966666666666667
print(np.mean(scores['fit_time'])) #2.230682706832886
- 교차 검증 점수 매우 높다. → 샘플(300개)보다 특성(10000개)이 훨씬 많기 때문에 과대적합된 모델을 만들기 쉽다.
- cross_validate() 함수가 반환한 값 : fit_time 항목에 각 교차 검증 폴드의 훈련시간 기록
→ 이 값을 PCA로 축소한 fruits_pca를 사용했을 때와 비교해본다.
scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score'])) #1.0
print(np.mean(scores['fit_time'])) #0.041118812561035153
- 정확도 : 100%, 훈련시간은 20배 이상 감소
→ PCA로 훈련 데이터의 차원을 축소하면 저장공간을 줄이고 모델 훈련 속도도 높일 수 있다. - n_components 매개변수 : 주성분 개수 대신 원하는 설명된 분산 비율 입력할 수 있다.
→ PCA 클래스는 지정된 비율에 도달할 때까지 자동으로 주성분을 찾는다.
#설명된 분산의 50%에 달하는 주성분을 찾도록 PCA 모델을 만든다.
#n_compoents : 0~1 사이의 비율을 실수로 입력한다.
pca = PCA(n_components=0.5)
pca.fit(fruits_2d)
#몇개의 주성분을 찾았는지 출력한다.
print(pca.n_components_) #2
- 2개의 특성만으로 원본 데이터에 있는 분산의 50%를 표현할 수 있다.
- 위 모델로 원본 데이터를 변환한다.
#주성분이 2개이므로 변환된 데이터의 크기는 (300,2)가 된다.
fruits_pca = pca.transform(fruits_2d)
- 2개의 특성만 사용한 모델의 교차 검증 결과를 확인해본다.
scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score'])) #0.9933333333333334
print(np.mean(scores['fit_time'])) #0.13310623168945312
- 차원 축소된 데이터를 사용해 k-평균 알고리즘으로 클러스터를 찾는다.
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_pca)
print(np.unique(km.labels_, return_counts=True))
#(array([0, 1, 2], dtype=int32), array([110, 99, 91])) -> 샘플 개수 (사과, 바나나, 파인애플)
#-> 원본 데이터를 사용했을 때와 결과가 비슷하다.
#과일 이미지 출력
for label in range(0,3):
draw_fruits(fruits[km.labels_ == label])
print("\n")
- n차원으로 표현하기 → fruits_pca 데이터는 2개의 특성이 있기 때문에 2차원으로 표현해본다.
- km.labels_를 사용해 클러스터별로 나누어 산점도를 그려본다.
for label in range(0, 3):
data = fruits_pca[km.labels_ == label]
plt.scatter(data[:,0], data[:,1])
plt.legend(['apple','banana','pineapple'])
plt.show()
정리 [주성분 분석으로 차원 축소]
- 차원 축소 : 원본 데이터의 특성을 적은 수의 새로운 특성으로 변환하는 비지도 학습의 한 종류
장점
- 데이터셋 크기를 줄이고 시각화하기 쉽다.
- 차원 축소된 데이터는 다른 알고리즘에서 재사용하여 성능을 높이거나 훈련 속도를 빠르게 할 수 있다. - 주성분 : 차원 축소 알고리즘의 하나로 데이터에서 가장 큰 분산이 큰 방향
주성분 분석 : 주성분을 찾는 방법 → 원본 데이터를 주성분에 투영하여 새로운 특성을 만들 수 있다. - 설명된 분산 : 주성분 분석에서 주성분이 얼마나 원본 데이터의 분산을 잘 나타내는지 기록한 것
- PCA 클래스
- 자동으로 설명된 분산을 계산하여 제공한다.
- 주성분의 개수를 명시적으로 지정하는 대신 설명된 분산의 비율을 설정하여 원하는 비율만큼 주성분을 찾을 수 있다.
- 변환된 데이터에서 원본 데이터를 복원하는 메서드 제공 → 변환된 데이터가 원본 데이터의 분산을 모두 유지하고 있어야 완벽하게 복원. 하지만 적은 특성으로도 상당 부분의 디테일을 복원할 수 있다.
'Study > PBL' 카테고리의 다른 글
[혼공머신] Ch07 (0) | 2024.07.24 |
---|---|
[혼공머신] Ch05 (0) | 2024.07.23 |
[혼공머신] Ch04 (0) | 2024.07.18 |
[혼공머신] Ch03 (0) | 2024.07.17 |
[혼공머신] Ch01, 2 (1) | 2024.07.12 |