PCA 주성분분석

형준·2021년 1월 18일
0

Linear Algebra

목록 보기
4/6

출처 : 공돌이의 수학정리노트,

PCA(Principal Component Analysis)는 주성분 분석이라고도 하며 고차원 데이터 집합이 주어졌을 때 원래의 고차원 데이터와 가장 비슷하면서 더 낮은 차원 데이터를 찾아내는 방법이다. 차원축소(dimension reduction)라고도 한다

PCA Process

1) 데이터를 X와 Y변수로 나눔

여기서 Y 란 "라벨" 혹은 "타겟"으로 우리가 궁극적으로 예측 하고자 하는 목표를 의미 합니다.

그리고 X란 데이터셋에서 Y를 예측하기 위한 모든 feature들을 의미합니다.

import numpy as np
X = np.array([[1,2],[3,4],[5,6]])

2) 각 행에 대해서 평균을 빼는 것으로 스케일을 조정함

이로써 각 행의 평균 값은 0이 됩니다. 이를 하지 않으면, 데이터 별로 스케일이 다르기 때문에 더 유의미한 분산을 찾는 과정의 효과가 사라집니다.

means=np.mean(X.T, axis=1)
centered_data = X-means #각 원소들에 means만큼 빼줌

3) 각 행에 대해서 표준편차로 나누어줌

2)와 3)과정을 통해 데이터셋의 모든 행은 각각 평균 0, 표준편차 1의 값을 가지게 될 것이고 이 두 과정을 합쳐서 데이터의 표준화, 정규화 ("standardizing") 라고 합니다.

std=np.std(X.T , axis=1)
standardized_data=centered_data / std

이후, 정규화된 매트릭스를 Z 매트릭스라고 부른다

4) Z의 분산-공분산 매트릭스를 계산함

ZTZZ^TZ를 통해 계산할 수 있다.

covariance_mat = np.cov(standardized_data.T)

5) 분산-공분산 매트릭스의 고유벡터와 고유값을 계산함

고유벡터는, 주어진 데이터에 대해서 분산을 가장 크게 유지시키는 역할을 합니다.

values, vectors = np.eig(covariance_mat)

6) 고유값, 고유벡터 쌍을 크기에 따라 정렬

일반적으로 고유값,고유 벡터는 여러개가 계산되며 이들의 크기는 데이터를 얼마나 분산시킬 수 있는 가와 연관이 있습니다. 즉, 가장 큰 쌍은 첫번째 Principal Component 로써 사용됩니다.

7) 데이터를 고유 벡터에 projection 시키는 것으로 매트릭스 변환을 함.

마지막 단계를 마치고 나면, 원래 데이터의 정보를 최대한 유지 하면서 차원을 줄이는 PCA를 마무리 지을 수 있습니다.

P = vectors.T.dot(standardized_data.T)

sklearn.decomposition.PCA

input:input :
n_components :: 정수 (PCA몇? = 2 또는 ~~~)
methodmethod :
fit_transform() : 특징행렬을 낮은 차원의 근사행렬로 변환 inverse_transform() : 변환된 근사행렬을 원래의 차원으로 복귀
attributesattributes :
mean_ : 평균벡터
components_ : 주성분벡터


실습 (n123a) Penguins

데이터셋 로드

from matplotlib import rc
import matplotlib.font_manager as fm
import matplotlib as mpl  # 기본 설정 만지는 용도
import matplotlib.pyplot as plt  # 그래프 그리는 용도
import matplotlib.font_manager as fm  # 폰트 관련 용도
import numpy as np
%matplotlib inline
##______________________________##^^
import seaborn as sns
import pandas as pd

dfraw = sns.load_dataset('penguins')
dfraw.dropna(axis=0,inplace=True)
dfraw.reset_index(drop=True, inplace=True)
dfraw.info()

정규화 진행

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
features=['bill_length_mm','bill_depth_mm','flipper_length_mm','body_mass_g']
categoricals=['species','island','sex']
x=dfraw.loc[:,features].values
y=dfraw.loc[:,categoricals].values

x=StandardScaler().fit_transform(x)
x


PCA진행

PCA를 진행한다. PCA자체가 Numerical 한 데이터에 대하여 진행하기때문이다.

pca=PCA(n_components=2)
principalComponents=pca.fit_transform(x)

principalDf=pd.DataFrame(data=principalComponents, columns=['pc1','pc2'])
finalDf=pd.concat([principalDf,dfraw[categoricals]], axis=1)
finalDf.head(10)

4개의 차원을 2개의 차원으로 축소하였다. (pc1, pc2)

주성분 벡터 즉, 가장 근사 데이터를 만드는 단위기저벡터는 components_ 속성에서 구할 수 있다

pca.components_

이후, 시각화 진행.

targets=dfraw.species.unique()
fig=plt.figure(figsize=(7,7))
ax=fig.add_subplot(1,1,1)
ax.set_xlabel('pc1',fontsize=15)
ax.set_ylabel('pc2',fontsize=15)
ax.set_title('2 component PCA',fontsize=18)

targets=list(dfraw.island.unique())
colors=['r','g','b']

for target,color in zip(targets,colors):
    indicesTokeep = finalDf['island']==target
    ax.scatter(finalDf.loc[indicesTokeep, 'pc1'],
               finalDf.loc[indicesTokeep,'pc2'],
               c=color,
               s=50
               )
ax.legend(targets)
ax.grid()

이미지로 하는 예제도 따라해보자
공돌이의 수학정리노트 - PCA

Scree Plot

그럼! 몇개의 PCA축을 사용해야할까? 를 판단해야할때, 고민에 빠지게된다.
일단 원본의 데이터를 최대한 유지하면서, 최소의 차원으로 낮추고싶으니까!
그럼 PCA축을 최소몇개를 써야할지, 정해야한다는것인데, 결국은 PCA축에 쭈르르륵 고차원데이터가 차원축소되고, 이것으로 프로그램을 실행시킬거니까 PCA축을 하나씩 늘려가면서 확인해보면되지 않을까? 에서 시작하였다.

PCA.explained_variance_ratio_ 를 사용하게되면서 쉬워졌다. 각 축의 분산도를 주는데 이것을 그래프처럼 그려보면, 한눈에 보고, 아 몇%까지는 pca의 n_components를 몇개를 지정하면되는구나~! 라고 생각하면 되니까!

def scree_plot(pca):
    num_components = len(pca.explained_variance_ratio_)
    ind = np.arange(num_components)
    vals = pca.explained_variance_ratio_
    
    
    ax = plt.subplot()
    cumvals = np.cumsum(vals)
    ax.bar(ind, vals, color = ['#00da75', '#f1c40f',  '#ff6f15', '#3498db']) # Bar plot
    ax.plot(ind, cumvals, color = '#c0392b') # Line plot 
    # ax.figure.figsize=(10,8)
    
    for i in range(num_components):
        ax.annotate(r"%s" % ((str(vals[i]*100)[:3])), (ind[i], vals[i]), va = "bottom", ha = "center", fontsize = 13)
    
    
    plt.xlim(0,num_components)
    ax.set_xlabel("PC")
    ax.set_ylabel("Variance")
    plt.title('Scree plot')
    
scree_plot(pca)
# plt.grid()
# plt.xlim(0,len(pca.explained_variance_ratio_))
# plt.title('Scree Plot')
# plt.xlabel('Num of Components')
# plt.ylabel('Explained Variance')
# plt.plot(pca.explained_variance_ratio_, 'o-')

이렇게 누적된 선과, 각각축의 비율을 나타내면, 아! 축이 2개 필요하겠구나! ok??


<img src='https://s3.us-west-2.amazonaws.com/secure.notion-static.com/467cd992-7c0f-4e4c-8f7c-ba6c931a9e9b/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20210126%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210126T071359Z&X-Amz-Expires=86400&X-Amz-Signature=452aea64786ff2849b94f77cbcb1284c26c96915b023af87af6129a9a2eab55c&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22Untitled.png%22', style='width=20px;'/>

profile
소프트웨어에 관심이 많은 학생입니다. 반갑습니다.

0개의 댓글

관련 채용 정보