본문 바로가기
머신러닝

머신러닝 - 차원 축소와 PCA (2)

by Tiabet 2023. 4. 14.

저번 포스팅에서 차원 축소와 그 기법 중 하나인 PCA에 대해서 정리했다.

 

이번엔 PCA를 직접 해보면서 더 감을 잡아보도록 하겠다. R과 파이썬 모두 PCA를 진행할 수는 있는데 우선 파이썬으로 진행하고 간단하게 정리해보려고 한다.

 

우선 실습을 위해 다음 패키지들을 import 해줘야 한다. PCA는 대부분의 기능이 그렇듯 싸이킷런에서 제공해주고 있다.

1
2
3
4
5
6
7
8
9
10
from pathlib import Path
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn import preprocessing
import matplotlib.pylab as plt
import dmba
 
%matplotlib inline
 
cs
1
2
3
cereals_df = dmba.load_data('Cereals.csv')
 
cereals_df
cs

dmba 패키지에 들어있는 데이터셋 중 Cereals.csv를 사용하고자 한다. 확인해보면 Cereals는 다음과 같은 데이터프레임을 볼 수 있다.

 

이 중에서 rating과 calories에 해당하는 column만 추출해서 PCA를 진행해보도록 하겠다.

 

1
2
3
4
5
6
7
8
9
pcs = PCA(n_components=2)
pcs.fit(cereals_df[['calories''rating']])
 
pcsSummary = pd.DataFrame({'Standard deviation': np.sqrt(pcs.explained_variance_),
                           'Proportion of variance': pcs.explained_variance_ratio_,
                           'Cumulative proportion': np.cumsum(pcs.explained_variance_ratio_)})
pcsSummary = pcsSummary.transpose()
pcsSummary.columns = ['PC1''PC2']
pcsSummary.round(4)
cs

 

calories와 rating 에 해당하는 칼럼들로부터 PC1, PC2를 추출해낸 뒤, PC들의 분산과 전체 분산 중 몇 퍼센트나 차지하는지를 확인할 수 있다. Weight vector, 즉 PC들의 기울기를 확인하려면 pcs.components_ 를 수행하면 된다.

 

1
2
3
pcsComponents_df = pd.DataFrame(pcs.components_.transpose(), columns=['PC1''PC2'], 
                                index=['calories''rating'])
pcsComponents_df
cs

 

PC1을 보면 calories 쪽으로 -0.847, rating 쪽으로 0.53 의 값을 가짐을 알 수 있다. 기울기를 따지자면 0.53/-0.84 가 되겠다. PC2 와 PC1는 서로 직각이기 때문에, PC2는 PC1의 값을 순서만 바꿔서 갖고 있음을 알 수 있다. 또한 Weight Vector의 크기는 1x2 인 것도 확인할 수 있다. (1 x 칼럼의 수 p, 본문에선 transpose를 취해줬음에 유의)

 

이제 Weight vector에 원래 데이터들을 사영시켜서 Scoring Vector를 얻어보자.

1
2
3
scores = pd.DataFrame(pcs.transform(cereals_df[['calories''rating']]), 
                      columns=['PC1''PC2'])
scores.head()
cs

 

데이터들이 PC1, PC2에 맞춰서 변환되었음도 확인할 수 있다. 이때 scores['PC1'].size()를 찍어보면 77이 나옴을 알 수 있다. Scoring Vector의 크기는 n x 1 임을 확인할 수 있는 부분이다.

1
2
3
4
5
6
7
8
pcs = PCA()
pcs.fit(cereals_df.iloc[:, 3:].dropna(axis=0))
pcsSummary_df = pd.DataFrame({'Standard deviation': np.sqrt(pcs.explained_variance_),
                           'Proportion of variance': pcs.explained_variance_ratio_,
                           'Cumulative proportion': np.cumsum(pcs.explained_variance_ratio_)})
pcsSummary_df = pcsSummary_df.transpose()
pcsSummary_df.columns = ['PC{}'.format(i) for i in range(1len(pcsSummary_df.columns) + 1)]
pcsSummary_df.round(4)
cs

이번엔 전체 데이터셋의 PC를 추출해보았다. 칼럼이 13개였으므로 13개의 PC가 추출되었다. 3행의 Cumulative proportion을 통해 주성분이 누적되면서 데이터셋의 분산을 얼마나 잘 표현하고 있는가를 확인할 수 있는데, PC2 까지는 92%, PC3 까지는 96%, PC4까지는 99%의 분산을 표현하고 있음이 보인다. 이때 몇 번째 주성분까지 선택하여 데이터를 다룰 지는 분석가의 선택이다. 하지만 PCA의 원래 목적이 차원 축소임을 감안하면, 13개의 PC를 모두 선택하는 것과 같은 실수만 하지 않으면 될 것이다. 나의 경우라면 증가율이 급격히 떨어지는 PC2까지 선택하여 분석을 우선 진행해보지 않을까 싶다.

 

다음 포스팅에선 PCA를 통해 clustering을 진행해보도록 하겠다.