[머신러닝] 차원축소 - 주성분 분석(PCA)

3 분 소요



차원

데이터가 가진 속성을 특성이라고 한다. 과일 사진의 경우 10000개의 픽셀이 있기 때문에 10000개의 특성이 있는 셈이다. 머신러닝에서는 이런 특성을 차원(dimension)이라고도 부른다.

10000개의 특성은 10000개의 차원이라는 건데 이 차원을 줄일 수 있다면 저장공간을 절약할 수 있다.

차원 축소

비지도 학습 작업 중 하나인 차원축소(dimensionality reduction) 알고리즘이 있다.

차원축소는 데이터를 가장 잘 나타내는 일부 특성을 선택해 데이터 크기를 줄이고 지도 학습 모델의 성능을 향상시킬 수도 있다.

또 줄어든 차원에서 다시 원본 차원으로 손실을 최대한 줄이면서 복원할 수 있다.

대표적인 차원 축소 알고리즘은 주성분 분석(principal component analysis)이 있다. 간단하게 PCA라고도 부른다.

주성분 분석

주성분 분석은 데이터에 있는 분산이 큰 방향을 찾는 것으로 이해할 수 있다. 분산은 데이터가 널리 퍼져있는 정도를 말한다. 분산이 큰 방향을 데이터로 잘 표현하는 벡터로 생각할 수 있다.

이 벡터를 주성분이라고 부른다. 이 주성분 벡터는 원본 데이터에 있는 어떤 방향이다. 따라서 주성분 벡터의 원소 개수는 원본 데이터셋에 있는 특성 개수와 같다. 하지만 원본 데이터는 주성분을 사용해 차원을 줄일 수 있다.

주성분은 원본 차원과 같고 주성분으로 바꾼 데이터는 차원이 줄어든다. 주성분이 가장 분산이 큰 방향이기 때문에 주성분에 투영하여 바꾼 데이터는 원본이 가지고 있는 특성을 가장 잘 나타내고 있을 것이다.

일반적으로 주성분은 원본 특성의 개수만큼 찾을 수 있다.

PCA 클래스

!wget https://bit.ly/fruits_300_data -O fruits_300.npy
import numpy as np

fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)
from sklearn.decomposition import PCA

pca = PCA(n_components=50)
pca.fit(fruits_2d)

n_components는 주성분의 개수이다.

print(pca.components_.shape)
(50, 10000)
print(fruits_2d.shape)
(300, 10000)
fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape)
(300, 50)

주성분을 찾았으니 원본 데이터를 주성분에 투영해 특성의 개수를 10000개에서 50개로 줄일 수 있다. 원본 데이터를 각 주성분으로 분해하는 것으로 생각할 수 있다. PCA의 transform 메서드를 사용해 원본 데이터의 차원을 50으로 줄였다.

fruits_2d 대신 fruits_pca를 저장한다면 저장공간을 절약할 수 있다.

원본 데이터 재구성

10000개의 특성에서 50개로 줄였다. 이로 인해 어느정도 손실이 발생할 수밖에 없다. 하지만 최대한 분산이 큰 방향으로 데이터를 투영했기 때문에 원본 데이터를 상당 부분 재구성할 수 있다.

fruits_inverse = pca.inverse_transform(fruits_pca)
print(fruits_inverse.shape)
(300, 10000)

inverse_transform 메서드를 통해 50개의 차원으로 축소된 것을 10000개의 특성을 복원했다.

복원한 데이터를 실제로 이미지로 출력해보면 일부 흐리고 번진 부분이 있지만 거의 모든 과일이 잘 복원되었다.

설명된 분산

주성분이 원본 데이터의 분산을 얼마나 잘 나타내는지 기록한 값을 설명된 분산(explained variance)라고 한다.

print(np.sum(pca.explained_variance_ratio_))
0.9215015476605593

PCA 클래스의 explained_variance_ratio_에 각 주성분의 설명된 분산 비율이 기록되어 있다. 당연히 첫번째 주성분의 설명된 분산이 가장 크다. 이 분산 비율을 모두 더하면 50개의 주성분으로 표현하고 있는 총 분산 비율을 얻을 수 있다.

92%가 넘는 분산을 유지하고 있다. 앞서 50개의 특성에서 원본 데이터를 복원했을 때 원본 이미지의 품질이 높았던 이유이다.

다른 알고리즘

비지도 학습말고 3개의 사진을 분류하는 지도학습에 사용해본다. 로지스틱 회귀 모델을 사용한다.

from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()

target = np.array([0] * 100 + [1] * 100 + [2] * 100)

from sklearn.model_selection import cross_validate

scores = cross_validate(lr, fruits_2d, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))
0.9966666666666667
1.8380496025085449

로지스틱 회귀 모델에서 성능을 가늠해 보기 위해 cross_validate로 교차검증을 한다. 교차 검증의 점수는 높다. 특성이 10000개나 되기 때문에 300개의 샘플에서는 금방 과대적합된 모델을 만들기 쉽다.

scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))
1.0
0.03938336372375488

PCA로 축소한 데이터와 비교했을 때 50개의 특성만 사용했을 때 정확도가 100%이고, 훈련시간도 0.03초로 20배 이상 감소했다.

PCA로 훈련 데이터의 차원을 축소하면 저장 공간뿐만 아니라 머신러닝 모델의 훈련속도도 높일 수 있다.

pca = PCA(n_components=0.5)
pca.fit(fruits_2d)

print(pca.n_components_)
2

PCA 클래스는 원하는 설명된 분산의 비율을 입력할 수 있다. PCA 클래스는 지정된 비율에 도달할 때가지 자동으로 주성분을 찾는다. 설명된 분산이 50%에 달하는 주성분을 찾도록 모델을 만든다. 그결과 2개의 특성만으로 원본 데이터에 있는 분산의 50%를 표현할 수 있다.

fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape)
(300, 2)

이 모델로 원본 데이터를 변환한다.

scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))
0.9933333333333334
0.048157548904418944

2개의 특성만 가지고 교차검증의 결과 99%의 정확도를 달성했다.

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([ 91,  99, 110]))

이번에는 2개의 특성만 가지고 k-평균 알고리즘으로 클러스터를 찾아보았다. 클러스터는 91,99,110개의 샘플을 포함하고 있다. 이는 원본데이터를 사용했을 때와 거의 비슷한 결과이다.

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

훈련데이터의 차원을 줄이면 얻을 수 있는 장점은 시각화이다. 3개 이하의 차원을 줄이면 화면에 출력하기 비교적 쉽다. fruits_pca 데이터는 2개의 특성이 있기 때문에 2차원으로 표현할 수 있다.

pca_clustering