출처 : 공돌이의 수학정리노트,
PCA(Principal Component Analysis)는 주성분 분석이라고도 하며 고차원 데이터 집합이 주어졌을 때 원래의 고차원 데이터와 가장 비슷하면서 더 낮은 차원 데이터를 찾아내는 방법이다. 차원축소(dimension reduction)라고도 한다
1) 데이터를 X와 Y변수로 나눔
여기서 Y 란 "라벨" 혹은 "타겟"으로 우리가 궁극적으로 예측 하고자 하는 목표를 의미 합니다.
그리고 X란 데이터셋에서 Y를 예측하기 위한 모든 feature들을 의미합니다.
import numpy as np
X = np.array([[1,2],[3,4],[5,6]])
이로써 각 행의 평균 값은 0이 됩니다. 이를 하지 않으면, 데이터 별로 스케일이 다르기 때문에 더 유의미한 분산을 찾는 과정의 효과가 사라집니다.
means=np.mean(X.T, axis=1)
centered_data = X-means #각 원소들에 means만큼 빼줌
2)와 3)과정을 통해 데이터셋의 모든 행은 각각 평균 0, 표준편차 1의 값을 가지게 될 것이고 이 두 과정을 합쳐서 데이터의 표준화, 정규화 ("standardizing") 라고 합니다.
std=np.std(X.T , axis=1)
standardized_data=centered_data / std
이후, 정규화된 매트릭스를 Z 매트릭스라고 부른다
를 통해 계산할 수 있다.
covariance_mat = np.cov(standardized_data.T)
고유벡터는, 주어진 데이터에 대해서 분산을 가장 크게 유지시키는 역할을 합니다.
values, vectors = np.eig(covariance_mat)
일반적으로 고유값,고유 벡터는 여러개가 계산되며 이들의 크기는 데이터를 얼마나 분산시킬 수 있는 가와 연관이 있습니다. 즉, 가장 큰 쌍은 첫번째 Principal Component 로써 사용됩니다.
마지막 단계를 마치고 나면, 원래 데이터의 정보를 최대한 유지 하면서 차원을 줄이는 PCA를 마무리 지을 수 있습니다.
P = vectors.T.dot(standardized_data.T)
n_components
:: 정수 (PCA몇? = 2 또는 ~~~)
:
fit_transform()
: 특징행렬을 낮은 차원의 근사행렬로 변환inverse_transform()
: 변환된 근사행렬을 원래의 차원으로 복귀
:
mean_
: 평균벡터
components_
: 주성분벡터
데이터셋 로드
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
그럼! 몇개의 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??