[범주형 데이터분석] 3. 주성분분석(PCA)
by Rev_주성분분석(PCA)은 차원 축소의 한 방법이다. 차원 축소(dimension reduction)란, feature 변수가 매우 많은 다차원 데이터 세트의 차원을 축소해서 새로운 차원의 데이터 세트를 만드는 방법이다.
* 피처(feature) : 데이터 세트의 속성이다. 학습용 데이터 세트가 반응을 분류하거나 예측하기 위해서는 몇몇의 예측 변수 표본이 필요한데, 여기서 예측 변수를 feature 라고 한다.
차원 축소는 왜 필요할까?
일반적으로 차원이 증가할 수록 데이터 포인트 간의 거리가 기하급수적으로 멀어진다. 그렇기에 수백 개 이상의 피처로 구성된 데이터 세트의 경우 상대적으로 적은 차원에서 학습된 모델보다 예측 신뢰도가 떨어짐
또한 피처가 많을 경우 개별 피처 간의 상관관계가 높을 가능성이 큰데, 그럴수록 다중공선성 문제로 모델의 예측 성능이 저하된다.
-> 그렇게 때문에 차원 축소를 통해 데이터를 시각적으로 압축하여 보기 편리하게 하고, 학습 데이터를 줄여 학습에 필요한 처리도 축소 시킬 수 있다.
* 다중공선성 : 회귀분석에서 독립변수들 간에 강한 상관관계가 나타나는 문제
- 피처 선택(feature selection), 피처 추출(feature extraction)
피처 선택 : 특정 피처에 종속성이 강한 불필요한 피처는 제거, 주요 피처만 선택
피처 추출 : 기존 피처를 저차원의 중요 피처로 압축해서 추출, 단순 압축 X
-> 이렇게 새롭게 추출된 중요 특성은 기존의 피처가 압축된 것이므로 기존의 피처와는 완전히 다른 값이 된다.
이런 잠재적인 요소를 찾는 피처 추출 알고리즘에 PCA, SVD, NMF 등이 있다.
- PCV 순서
1. 입력 데이터 세트의 공분산 행렬 생성
2. 공분산 행렬의 고유벡터와 고유값 계산
3. 고유값이 가장 큰 순으로 K개(PCV 변환 차수 만큼)만큼 고유벡터를 추출
4. 고유값이 가장 큰 순으로 추출된 고유벡터를 이용해 새롭게 입력 데이터 변환
IRIS 데이터 분석
iris 데이터를 통하여 주성분분석을 연습해보자.
from sklearn.datasets import load_iris
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
iris = load_iris()
iris.keys()
[Out] dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
iris.key()
는 iris 데이터셋의 컬럼 값을 출력하는 함수이다.
대표적으로 data 컬럼은 아이리스 데이터가 있는 부분이며, feature_names는 데이터의 특징을 모아둔 것이다.
iris.feature_names
[Out] ['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)']
iris data 값의 변수들이라고 할 수 있다.
columns = ['sepal_length','sepal_width','petal_length','petal_width']
irisDF = pd.DataFrame(iris.data , columns=columns)
irisDF[:3]
featrue_names에서 각각 뒤에 붙은 (cm)을 없애주기 위해 각각의 내용을 columns으로 저장해주었다.
그래서 iris.data에 각 특성들을 컬럼으로 지정해서 데이터프레임을 생성했다.
irisDF.cov()
4개의 feature 변수에 대해 공분산행렬을 구해보았다.
공분산은 한 개의 특정한 변수의 데이터 변동을 의미하는 분산과 달리, 두 변수 간의 변동을 의미한다. 대각선 원소는 각 변수의 분산이라고 해석할 수 있다.
변수들을 표준화하지 않았으므로 분산값들이 서로 꽤 다르다.
irisDF['target']=iris.target
이 데이터프레임에 타겟변수도 추가해주었다.
target variable(목표 변수)는 모델을 만들 때 사용자가 예측하고자 하는 값을 의미한다.
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()
네 변수 중 두 변수(sepal_length, sepal_width)로만 그림을 그려보았다.
setosa의 target 값은 0, versicolor는 1, virginica는 2로 구분된다. markers의 순서로 각각 다른 모양으로 시각화 해보았다. ^는 세모, s는 네모, o는 동그라미를 의미한다.
Setosa 품종의 경우 sepal width가 3보다 크고, sepal length는 6보다 작은 곳에 일정하게 분포되어 있는 것을 알 수 있다. 하지만 Versicolor와 Virginica 품종은 위의 두 변수만으로는 구분하기 어려운 감이 있다.
그렇다면 PCA 방법으로 4개의 변수를 둘로 압축해보자.
먼저 붓꽃 데이터 세트에 바로 PCA를 적용하기 전에 개별 속성을 함께 스케일링 해야한다. PCA는 여러 속성의 값을 연산해야 하므로 속성의 스케일에 영향을 받는다.
from sklearn.preprocessing import StandardScaler
iris_scaled = StandardScaler().fit_transform(irisDF.iloc[:, :-1])
사이킷런의 StandardScaler().fit_transform()
를 이용하여 평균이 0, 분산이 1인 표준 정규 분포로 데이터 세트의 속성값들을 변환했다. (타겟값 제외)
이제 스케일링이 적용된 데이터 세트에 PCA를 적용해 4차원(4개 속성)의 데이터를 2차원(2개의 PCA 속성) PCA 데이터로 변환해보자.
사이킷런은 PCA 변환을 위한 PCA 클래스를 제공한다!
from sklearn.decomposition import PCA
pca = PCA(n_components = 2)
pca.fit(iris_scaled)
iris_pca = pca.transform(iris_scaled)
print(iris_pca.shape)
[Out] (150, 2)
iris_pca이 150 X 2 행렬이 되었다.
sklearn.decomposition 안에 있는 클래스 PCA의 객체를 만들었다. 클래스 PCA는 생성 파라미터로 n_components를 입력 받는데, 이것은 PCA로 변환할 차원의 수를 의미한다.
이후에 fit과 transform을 호출해 PCA 변환을 수행한 데이터를 iris_pca 변수에 담았다.
fit과 transform 메서드에 대해 알아보자면,
fit()은 학습 데이터 세트에서 변환을 위한 기반을 설정하는 단계이다. StandardScaler 객체를 생성한 후 fit()에 학습 데이터 세트를 인자로 넣어주면, 학습 데이터 세트의 변환을 위한 여러가지 기반을 설정한 후 그 값을 내부에 저장한다.
transform()은 fit()에서 저장된 설정값들을 기반으로 데이터를 변환하는 역할을 한다.
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)
원래 4개 였던 변수가 둘로 압축되었다!
새 변수를 각각 'pca_component_1', 'pca_component_2' 라고 하였다.
여기에 타겟 변수 컬럼을 추가하여 irisDF_pca 라는 데이터 프레임을 만들었다.
이제 변수가 2개이기 때문에 평면상에 시각화할 수 있다.
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()
pca_component_1 속성을 X축으로, pca_component_2 속성을 Y축으로 하여 시각화하였다.
versicolor와 virginica 품종이 약간 섞여 있긴 하지만 두 개의 새로운 변수가 세 품종을 비교적 잘 분류했다고 할 수 있다.
각 변수가 원본 데이터의 변동성을 얼마나 반영하고 있는지 알아보자.
PCA 객체의 explained_variance_ratio_ 속성은 전체 변동성에서 개별 PCA 컴포넌트별로 차지하는 변동성 비율을 제공하고 있다.
print(pca.explained_variance_ratio_)
[Out] [0.72962445 0.22850762]
첫 번째 축이 약 73%, 두 번째 축이 약 23%를 설명한다. 즉 두 축이 전체 변동의 96% 정도를 설명하고 있는 것이다.
원본 데이터와 변환된 데이터를 각각 랜덤포레스트 방법으로 분류한 후 정확도를 비교해보자.
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
rcf = RandomForestClassifier(random_state=156)
scores = cross_val_score(rcf, iris.data, iris.target,scoring='accuracy',cv=3)
print('원본 데이터 교차 검증 개별 정확도:',scores)
print('원본 데이터 평균 정확도:', np.mean(scores))
[Out] 원본 데이터 교차 검증 개별 정확도: [0.98 0.94 0.96]
원본 데이터 평균 정확도: 0.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('PCA 변환 데이터 교차 검증 개별 정확도:',scores_pca)
print('PCA 변환 데이터 평균 정확도:', np.mean(scores_pca))
[Out] PCA 변환 데이터 교차 검증 개별 정확도: [0.88 0.88 0.88]
PCA 변환 데이터 평균 정확도: 0.88
변수의 수를 줄인 데이터로 분류하면 당연히 정확도는 떨어지지만 두 개의 변수만으로 데이터의 변동을 상당히 잘 설명하고 있다.
'복수전공' 카테고리의 다른 글
[실험계획법] 2. 기초적 통계이론 (0) | 2021.10.31 |
---|---|
[SAS 자료분석] 2. SAS 데이터 단계 (0) | 2021.10.31 |
[데이터 시각화] 5. 모자이크 플롯 (0) | 2021.10.27 |
[SAS 자료분석] 1. SAS파일 다루기 (0) | 2021.10.25 |
[범주형 데이터분석] 2. 선형대수학(Linear Algebra) (0) | 2021.10.25 |
블로그의 정보
Hi Rev
Rev_