본문 바로가기

Lecture ML

머신러닝 강좌 #32] 차원 축소 : PCA(Principal Component Analysis)

반응형

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

 

이를 위해서 PCA는 가장 높은 분산을 가지는 데이터의 축을 찾아 이 축으로 차원을 축소하는데, 이것이 PCA의 주성분입니다. PCA, 즉 주성분 분석은 이처럼 원본 데이터의 피처 개수에 비해 매우 작은 주성분으로 원본 데이터의 총 변동성으로 대부분 설명할 수 있는 분석법입니다.

 

정리하면 PCA는 입력 데이터의 공분산 행렬이 고유벡터와 고유값으로 분해될 수 있으며, 이렇게 분해된 고유벡터를 이용해 입력 데이터를 선형 변환하는 방식이 PCA라는 것입니다. 보통 PCA는 다음과 같은 스텝으로 수행됩니다.

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

# 사이킷런 내장 데이터 셋 API 호출
iris = load_iris()

# 넘파이 데이터 셋을 Pandas DataFrame으로 변환
columns = ['sepal_length','sepal_width','petal_length','petal_width']
irisDF = pd.DataFrame(iris.data , columns=columns)
irisDF['target']=iris.target
irisDF.head(3)

markers=['^', 's', 'o']

#setosa의 target 값은 0, versicolor는 1, virginica는 2. 각 target 별로 다른 shape으로 scatter plot 
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()

Setosa품종의 경우 sepal width가 3.0보다 크고, sepal length가 6.0이하인 일정하게 분포돼 있습니다. Versicolor와 Virginica의 경우는 sepal width와 sepal length조건만으로는 분류가 어려운 복잡한 조건임을 알 수 있습니다.

 

이제 PCA로 4개 속성을 2개로 압축한 뒤 앞의 예제와 비슷하게 2개의 PCA속성으로 붓꽃 데이터의 품종 분포를 2차원으로 시각화해 보겠습니다.

 

먼저 붓꽃 데이터 세트에 바로 PCA를 적용하기 전에 개별 속성을 함께 스케일링해야 합니다. PCA는 여러 속성의 값을 연산해야 하므로 속성의 스케일에 영향을 받습니다. 따라서 여러 속성을 PCA로 압축하기 전에 각 속성값을 동일한 스케일로 변환하는 것이 필요합니다.

 

from sklearn.preprocessing import StandardScaler

iris_scaled = StandardScaler().fit_transform(irisDF)

 

이제 스케일링이 적용된 데이터 세트에 PCA를 적용해 4차원의 붓꽃 데이터를 2차원 PCA데이터로 변환해 보겠습니다. 

from sklearn.decomposition import PCA

pca = PCA(n_components=2)

#fit( )과 transform( ) 을 호출하여 PCA 변환 데이터 반환
pca.fit(iris_scaled)
iris_pca = pca.transform(iris_scaled)
print(iris_pca.shape)

 

DataFrame으로 변환한 뒤 데이터값을 확인해 보겠습니다.

# PCA 환된 데이터의 컬럼명을 각각 pca_component_1, pca_component_2로 명명
pca_columns=['pca_component_1','pca_component_2']
irisDF_pca = pd.DataFrame(iris_pca,columns=pca_columns)
irisDF_pca['target']=iris.target
irisDF_pca.head(3)

 

각 데이터가 어떻게 분포되어 있는지 확인해보겠습니다.

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

#pca_component_1 을 x축, pc_component_2를 y축으로 scatter plot 수행. 
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()

 

PCA Component별로 원본 데이터의 변동성을 얼마나 반영하고 있는지 알아보겠습니다. PCA변환을 수행한 PCA객체의 explained_variance_ratio_ 속성은 전체 변동성에서 개별 PCA컴포넌트별로 차지하는 변동성 비율을 제공하고 있습니다.

print(pca.explained_variance_ratio_)

결과는 아래와 같습니다.

[0.76740358 0.18282727]

 

해석을 한다면 pca_component_1이 전체 변동성의 약 76.7%를 차지하며, 두 번째인 pca_component_2가 약 18.2%를 차지합니다. PCA를 2개 요소로만 변환해도 원본 데이터의 변동성을 95% 설명할 수 있습니다.

 

각 데이터의 정확성을 비교해서 보겠습니다.


from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import numpy as np

rcf = RandomForestClassifier(random_state=156)
scores = cross_val_score(rcf, iris.data, iris.target,scoring='accuracy',cv=3)
print(scores)
print(np.mean(scores))

# 96%

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(scores_pca)
print(np.mean(scores_pca))

# 86%

 

일반적으로 PCA변환 차원 개수에 따라 예측 성능이 떨어질 수밖에 없습니다. 하지만 대부분 유지하고 있음을 알 수 있습니다.

반응형