본문 바로가기

ML with SckitLearn

PCA(Principal Component Analysis) : 차원축소(Dimension Reduction)

반응형

1. PCA개요

PCA(Principal Component Analysis)는 가장 대표적인 차원 축소 기법입니다. 여러 변수 간에 존재하는 상관관계를 이용해 이를 대표하는 주성분(Principan component)을 추출해 차원을 축소하는 기법입니다. PCA로 차원을 축소할 때는 기존 데이터의 정보 유실이 최소화되는 것이 당연합니다. 

이를 위해서 PCA는 가장 높은 분산을 가지는 데이터의 축을 찾아 이 축으로 차원을 축소하는데, 이것이 PCA의 주성분이 됩니다. (즉, 분산이 데이터의 특성을 가장 잘 나타내는 것으로 간주합니다.)

 

2. PCA Process Step

  1. 입력 데이터 세트의 공분산 행렬을 생성합니다.
  2. 공분산 행렬의 고유벡터와 고유값을 계산합니다.
  3. 고유값이 가장 큰 순으로 K개(PCA 변환 차수만큼)만큼 고유벡터를 추출합니다.
  4. 고유값이 가장 큰 순으로 추출된 고유벡터를 이용해 새롭게 입력 데이터를 변환합니다.

 

3. PCA Examle

공통으로 사용할 library를 import합니다.

from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

 

Iris Data의 Data Set는 sepal length, sepal width, petal length, petal width의 4개의 속성을 PCA를 이용하여 2개의 차원으로 변환해보겠습니다. 

 

첫번째, Iris Data Set 확인하기

iris = load_iris()
columns = ['sepal_length','sepal_width','petal_length','petal_width']
irisDF = pd.DataFrame(iris.data, columns=columns)
irisDF['target']=iris.target
print(irisDF)

 

두번째, 각 품종에 따라 분포도를 2차원으로 시각화합니다. sepal length와 sepal width를 X, Y축으로 나타냅니다.  결과를 보면 setosa는 분류가 되나 versicolor와 virginia는 분류가 어렵다는 것을 알 수 있습니다. 이제 PCA로 4개 속성을 2개로 압축하여 2차원으로 시각해 봅니다.

markers=['^','s','o']
for i, marker in enumerate(markers):
    x_axis_data = irisDF[irisDF['target']==i]['sepal_length']
    y_axis_data = irisDF[irisDF['target']==i]['sepal_width']
    plt.scatter(x_axis_data, y_axis_data, marker=marker, label=iris.target_names[i])

plt.legend()
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.show()

 

세번째, PCA를 적용하기 전에 개별 속성을 함께 스케일링해야 합니다. PCA는 여러 속성의 값을 연산해야 하므로 속성의 스케일에 영향을 받으므로, 여러 속성을 PCA로압축하기 전에 각 속성값을 동일한 스케일로 변환하는 것이 필요합니다. 

 

이 때 이용하는 것이 사이킷런의 StandardScaler를 이용해 평균이 0, 분산이 1인 표준 정규 분포로 데이타 속성을 변한합니다. 이 후 PCA를 이용해 2차원으로 변환합니다. 이 떄 사용하는 것이 n_components입니다. 2라고 하면 2차원으로 변환합니다. 

 

이를 dataframe에 넣어 데이타값을 확인하는 방법까지의 절차를 확인해봅니다.

#Target값을 제외한 모든 속성 값을 StandardScaler를 이용해 표준 정규 분포를 가지는 값들로 변환
iris_scaled = StandardScaler().fit_transform(irisDF.iloc[:,:-1])

#2차원으로 PCA 차원축소, fit()과 transform()을 이용하여 PCA 변환 데이터 반환
pca = PCA(n_components=2)
pca.fit(iris_scaled)
iris_pca = pca.transform(iris_scaled)
print(iris_pca.shape)

#PCA 변환된 데이터의 칼럼명을 명명
pca_columns=['pca_component_1','pca_component_2']
irisDF_pca = pd.DataFrame(iris_pca, columns=pca_columns)
irisDF_pca['target'] = iris.target
print(irisDF_pca)

 

네번째, 차원축소된 Iris데이타의 분포를 확인합니다.

#setosa를 세모, versicolor를 네모, virginica를 동그라미로 표시
markers=['^','s','o']

#분포 확인
for i, marker in enumerate(markers):
    x_axis_data = irisDF_pca[irisDF_pca['target']==i]['pca_component_1']
    y_axis_data = irisDF_pca[irisDF_pca['target']==i]['pca_component_2']
    plt.scatter(x_axis_data, y_axis_data, marker=marker, label=iris.target_names[i])

plt.legend()
plt.xlabel('pca_component_1')
plt.ylabel('pca_component_2')
plt.show()

 

다섯번째, 상기 결과를 확인하면 virginica와 versicolor의 일부 데이타가 겹치지만 비교적 잘 구분이 되어 있습니다. 그렇다면 PCA Component별로 원본 데이터의 변동성을 얼마나 반영하고 있는지 알아보겠습니다. 

 

PCA객체의 explained_variance_ratio_속성은 전체 변동성에서 개별 PCA컴포넌트별로 차지하는 변동성 비율을 제공합니다.  추가로 cross_val_score()로 3개의 교차 검증 세트로 정확도 결과를 비교합니다.

print(pca.explained_variance_)

rcf = RandomForestClassifier(random_state=156)
scores = cross_val_score(rcf, iris.data, iris.target, scoring='accuracy', cv=3)
print('원본 데이터 교차 검증 개별 정확도', scores)
print('원본 데이터 평균 정확도', np.mean(scores))

pca_X = irisDF_pca[['pca_component_1','pca_component_2']]
scores_pca = cross_val_score(rcf, pca_X, iris.target, scoring='accuracy', cv=3)
print('PCA 원본 데이터 교차 검증 개별 정확도', scores_pca)
print('PCA 원본 데이터 평균 정확도', np.mean(scores_pca))
#Result
[2.93808505 0.9201649 ]
원본 데이터 교차 검증 개별 정확도 [0.98 0.94 0.96]
원본 데이터 평균 정확도 0.96
PCA 원본 데이터 교차 검증 개별 정확도 [0.88 0.88 0.88]
PCA 원본 데이터 평균 정확도 0.88

 

반응형