주성분분석
여러 특성(feature) 가운데 대표 특성을 찾아 분석하는 방식으로, 자료의 차원을 고차원에서 하위 차원으로 축소하는 차원축소
기법을 활용한다.
분산, 차원축소를 위한 주성분의 선택 기준
차원축소를 위한 정사영의 시작은 무엇을 기준으로 선택되는 걸까?
선택에 따라 데이터의 실제 특성을 보존할 수도 있고, 잃을 수도 있다.
주성분 선택에 있어 최초로 고려되는 요소는 8분산이 가장 큰 하나의 데이터 선이 된다. 분산을 기준으로 첫 번째 주성분을 찾아낸다. 분산이 가장 큰 경우가 데이터의 변동 방향을 가장 잘 설명하는 첫 번째 주성분 값이 되며, 그것에 직교하는 선이 두 번째 주성분이 된다.
직교, 그 다음 주성분을 찾는 기준
두 번째 주성분은 첫 번째 주성분과 직교
하는 또 하나의 선이다. 첫 번째 선택 방향과 직교하면서 첫 번째로 분산이 큰 쪽이 선택된다. 두 선이 직교하고 있다면 하나의 선과 다른 하나의 선은 서로 가장 독립적인 상태라고 말할 수 있다. 이를 내적이 0인 상태라고 하는데, 좌표상에 두 선이 수직을 이루며 교차함을 뜻한다.
차원축소의 3가지 순기능
주성분 분석을 사용하는 이유는 데이터가 가진 특성의 수가 지나치게 많을 때, 그 수를 적절하게 줄임으로써 얻어지는 이점이 있기 때문이다. 특성의 수를 줄일 때 우리는 크게 3가지 순기능을 기대해볼 수 있다.
- 차원이 낮아지면 대상에 대한 이해가 보다 쉬워지게 된다.
- 연산속도가 개선된다. 분산값을 유지하면서 정보의 크기 자체를 줄이기 때문에 데이터 특성을 훼손시키지 않고도 보다 빠른 연산을 기대할 수 있게 된다.
- 차원축소는
차원의 저주
를 해결하는 열쇠가 된다. 만약 데이터 양이 동일한 경우에 보다 상위 차원 속에 데이터를 위치시키면 데이터간의 거리가 점점 멀어지게 된다. 면적당 데이터의 수가 떨어진다는 것이다. 이런 문제를 차원의 저주라고 한다. 차원 증가에 따라 요구되는 데이터의 양이 기하급수적으로 늘어나기 때문에 차원축소를 통해 이와 같은 문제를 해결한다. 또한 차원축소는 데이터가 부족한 상태에서 과적합을 예방하는 전처리 기법으로도 사용 가능하다.
Library Import
1
2
3
4
5
6
7
8
| import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
|
Data Load
1
2
3
4
5
6
| cancer = load_breast_cancer()
df = pd.DataFrame(cancer.data, columns=cancer.feature_names)
y = pd.Series(cancer.target, dtype='category')
df['class'] = y
|
| mean radius | mean texture | mean perimeter | mean area | mean smoothness | mean compactness | mean concavity | mean concave points | mean symmetry | mean fractal dimension | ... | worst texture | worst perimeter | worst area | worst smoothness | worst compactness | worst concavity | worst concave points | worst symmetry | worst fractal dimension | class |
---|
0 | 17.99 | 10.38 | 122.80 | 1001.0 | 0.11840 | 0.27760 | 0.3001 | 0.14710 | 0.2419 | 0.07871 | ... | 17.33 | 184.60 | 2019.0 | 0.1622 | 0.6656 | 0.7119 | 0.2654 | 0.4601 | 0.11890 | 0 |
---|
1 | 20.57 | 17.77 | 132.90 | 1326.0 | 0.08474 | 0.07864 | 0.0869 | 0.07017 | 0.1812 | 0.05667 | ... | 23.41 | 158.80 | 1956.0 | 0.1238 | 0.1866 | 0.2416 | 0.1860 | 0.2750 | 0.08902 | 0 |
---|
2 | 19.69 | 21.25 | 130.00 | 1203.0 | 0.10960 | 0.15990 | 0.1974 | 0.12790 | 0.2069 | 0.05999 | ... | 25.53 | 152.50 | 1709.0 | 0.1444 | 0.4245 | 0.4504 | 0.2430 | 0.3613 | 0.08758 | 0 |
---|
3 | 11.42 | 20.38 | 77.58 | 386.1 | 0.14250 | 0.28390 | 0.2414 | 0.10520 | 0.2597 | 0.09744 | ... | 26.50 | 98.87 | 567.7 | 0.2098 | 0.8663 | 0.6869 | 0.2575 | 0.6638 | 0.17300 | 0 |
---|
4 | 20.29 | 14.34 | 135.10 | 1297.0 | 0.10030 | 0.13280 | 0.1980 | 0.10430 | 0.1809 | 0.05883 | ... | 16.67 | 152.20 | 1575.0 | 0.1374 | 0.2050 | 0.4000 | 0.1625 | 0.2364 | 0.07678 | 0 |
---|
5 rows × 31 columns
양성/악성 정보 바탕의 진단 결과를 속성별 관계로 플로팅하여 환자 분포의 분명한 차이를 시각적으로 확인한다.
1
2
| sns.pairplot(vars=['mean radius', 'mean texture', 'mean area', 'mean concavity'], hue='class', data=df)
plt.show()
|
Scailing
주성분 분석을 사용하기 전 표준화 또는 정규화 작업이 필요하다. 속성마다 데이터값의 범위가 다르기 때문에 이를 주성분 선별 전에 전처리해야 각 속성의 영향도를 같은 선상에서 비교할 수 있다.
1
2
3
| # 표준화
scale = StandardScaler()
x_scaled = scale.fit_transform(cancer.data)
|
PCA
1
2
3
4
| from sklearn.decomposition import PCA
pca = PCA(n_components=8)
comp = pca.fit_transform(x_scaled)
|
1
2
3
4
| pca_df = pd.DataFrame(comp, columns=['Comp1', 'Comp2', 'Comp3', 'Comp4', 'Comp5', 'Comp6', 'Comp7', 'Comp8'])
print(pca_df.shape)
pca_df.head()
|
| Comp1 | Comp2 | Comp3 | Comp4 | Comp5 | Comp6 | Comp7 | Comp8 |
---|
0 | 9.192837 | 1.948583 | -1.123166 | 3.633731 | -1.195110 | 1.411424 | 2.159342 | -0.398406 |
---|
1 | 2.387802 | -3.768172 | -0.529293 | 1.118264 | 0.621775 | 0.028656 | 0.013357 | 0.240987 |
---|
2 | 5.733896 | -1.075174 | -0.551748 | 0.912083 | -0.177086 | 0.541451 | -0.668195 | 0.097374 |
---|
3 | 7.122953 | 10.275589 | -3.232790 | 0.152547 | -2.960878 | 3.053423 | 1.429936 | 1.059571 |
---|
4 | 3.935302 | -1.948072 | 1.389767 | 2.940639 | 0.546748 | -1.226493 | -0.936165 | 0.636379 |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 표준편차
pca_std = pd.DataFrame(pca_df.std()).T
# 각 주성분의 설명된 분산 비율
pca_var = pd.DataFrame(pca.explained_variance_ratio_.T).set_index(pca_std.columns).T
# 누적 기여율
pca_cumsum = pd.DataFrame(pca.explained_variance_ratio_.cumsum()).set_index(pca_std.columns).T
pca_summary = pd.concat([pca_std, pca_var, pca_cumsum])
pca_summary.index = ['Standard deviation', 'Propotion of variance', 'Cumulative proportion']
pca_summary
|
| Comp1 | Comp2 | Comp3 | Comp4 | Comp5 | Comp6 | Comp7 | Comp8 |
---|
Standard deviation | 3.647601 | 2.387755 | 1.680152 | 1.408591 | 1.285159 | 1.099765 | 0.822441 | 0.690982 |
---|
Propotion of variance | 0.442720 | 0.189712 | 0.093932 | 0.066021 | 0.054958 | 0.040245 | 0.022507 | 0.015887 |
---|
Cumulative proportion | 0.442720 | 0.632432 | 0.726364 | 0.792385 | 0.847343 | 0.887588 | 0.910095 | 0.925983 |
---|
1
| per_var = np.round(pca.explained_variance_, 1)
|
Scree Plot
Scree Plot을 활용하여 고유값이 수평을 유지하기 전단계로 주성분의 수를 결정한다.
1
2
3
4
5
| plt.figure(figsize=(8, 6))
plt.title('Scree Plot', fontsize=15)
plt.plot(range(1, 9), per_var,
marker='o', markerfacecolor='w', markersize=6, markeredgecolor='k', color='r')
plt.show()
|
PCA 계산 과정
고유벡터
: 고유벡터는 주성분(P)와 표준화된 독립변수(Z) 사이의 관계를 보여준다.
- PC1 = 0.218902(X1) + 0.103725(X2) + … + 0.131784(X30)
- cancer 데이터가 target 변수를 제외하고 총 30개의 변수를 갖고 있으므로 index 0~29를 갖는 고유벡터가 생성된다.
1
2
3
| pca_vector = pd.DataFrame(pca.components_.T)
pca_vector.columns = ['PC1', 'PC2', 'PC3', 'PC4', 'PC5', 'PC6', 'PC7', 'PC8']
pca_vector
|
| PC1 | PC2 | PC3 | PC4 | PC5 | PC6 | PC7 | PC8 |
---|
0 | 0.218902 | -0.233857 | -0.008531 | 0.041409 | 0.037786 | 0.018741 | -0.124086 | -0.007452 |
---|
1 | 0.103725 | -0.059706 | 0.064550 | -0.603050 | -0.049469 | -0.032179 | 0.011400 | 0.130675 |
---|
2 | 0.227537 | -0.215181 | -0.009314 | 0.041983 | 0.037375 | 0.017308 | -0.114474 | -0.018687 |
---|
3 | 0.220995 | -0.231077 | 0.028700 | 0.053434 | 0.010331 | -0.001888 | -0.051652 | 0.034674 |
---|
4 | 0.142590 | 0.186113 | -0.104292 | 0.159383 | -0.365089 | -0.286375 | -0.140670 | -0.288975 |
---|
5 | 0.239285 | 0.151892 | -0.074092 | 0.031795 | 0.011704 | -0.014131 | 0.030920 | -0.151396 |
---|
6 | 0.258400 | 0.060165 | 0.002734 | 0.019123 | 0.086375 | -0.009344 | -0.107521 | -0.072827 |
---|
7 | 0.260854 | -0.034768 | -0.025564 | 0.065336 | -0.043861 | -0.052050 | -0.150484 | -0.152323 |
---|
8 | 0.138167 | 0.190349 | -0.040240 | 0.067125 | -0.305941 | 0.356458 | -0.093892 | -0.231531 |
---|
9 | 0.064363 | 0.366575 | -0.022574 | 0.048587 | -0.044424 | -0.119431 | 0.295760 | -0.177121 |
---|
10 | 0.205979 | -0.105552 | 0.268481 | 0.097941 | -0.154456 | -0.025603 | 0.312490 | 0.022540 |
---|
11 | 0.017428 | 0.089980 | 0.374634 | -0.359856 | -0.191651 | -0.028747 | -0.090755 | -0.475413 |
---|
12 | 0.211326 | -0.089457 | 0.266645 | 0.088992 | -0.120990 | 0.001811 | 0.314642 | -0.011897 |
---|
13 | 0.202870 | -0.152293 | 0.216007 | 0.108205 | -0.127574 | -0.042864 | 0.346678 | 0.085805 |
---|
14 | 0.014531 | 0.204430 | 0.308839 | 0.044664 | -0.232066 | -0.342917 | -0.244024 | 0.573410 |
---|
15 | 0.170393 | 0.232716 | 0.154780 | -0.027469 | 0.279968 | 0.069197 | 0.023462 | 0.117460 |
---|
16 | 0.153590 | 0.197207 | 0.176464 | 0.001317 | 0.353982 | 0.056343 | -0.208822 | 0.060567 |
---|
17 | 0.183417 | 0.130322 | 0.224658 | 0.074067 | 0.195548 | -0.031224 | -0.369645 | -0.108319 |
---|
18 | 0.042498 | 0.183848 | 0.288584 | 0.044073 | -0.252869 | 0.490246 | -0.080383 | 0.220149 |
---|
19 | 0.102568 | 0.280092 | 0.211504 | 0.015305 | 0.263297 | -0.053195 | 0.191394 | 0.011168 |
---|
20 | 0.227997 | -0.219866 | -0.047507 | 0.015417 | -0.004407 | -0.000291 | -0.009711 | 0.042619 |
---|
21 | 0.104469 | -0.045467 | -0.042298 | -0.632808 | -0.092883 | -0.050008 | 0.009870 | 0.036251 |
---|
22 | 0.236640 | -0.199878 | -0.048547 | 0.013803 | 0.007454 | 0.008501 | -0.000446 | 0.030558 |
---|
23 | 0.224871 | -0.219352 | -0.011902 | 0.025895 | -0.027391 | -0.025164 | 0.067828 | 0.079394 |
---|
24 | 0.127953 | 0.172304 | -0.259798 | 0.017652 | -0.324435 | -0.369255 | -0.108830 | 0.205852 |
---|
25 | 0.210096 | 0.143593 | -0.236076 | -0.091328 | 0.121804 | 0.047706 | 0.140473 | 0.084020 |
---|
26 | 0.228768 | 0.097964 | -0.173057 | -0.073951 | 0.188519 | 0.028379 | -0.060489 | 0.072468 |
---|
27 | 0.250886 | -0.008257 | -0.170344 | 0.006007 | 0.043332 | -0.030873 | -0.167969 | -0.036171 |
---|
28 | 0.122905 | 0.141883 | -0.271313 | -0.036251 | -0.244559 | 0.498927 | -0.018489 | 0.228225 |
---|
29 | 0.131784 | 0.275339 | -0.232791 | -0.077053 | 0.094423 | -0.080223 | 0.374659 | 0.048361 |
---|
1
2
3
| # StandardScaler로 표준화된 x값들에 대한 데이터 프레임
x_df = pd.DataFrame(x_scaled, columns=cancer.feature_names)
|
1
2
3
4
5
6
7
8
9
10
11
| # 상관 행렬
# 스케일링한 x 데이터를 이용한다.
corr = x_df.corr(method = 'pearson')
# (w = 고유값),(v = 고유벡터), (corr.values=DataFrame인 corr를 numpy array로 변환)
w, v = np.linalg.eig(corr.values)
# 고유값
eig_value = pd.DataFrame(w[:8], columns=['eigenvalue'], index=['PC1', 'PC2', 'PC3', 'PC4', 'PC5', 'PC6', 'PC7', 'PC8'])
eig_value = eig_value.T # or eig_value.transpose()
eig_value
|
| PC1 | PC2 | PC3 | PC4 | PC5 | PC6 | PC7 | PC8 |
---|
eigenvalue | 13.281608 | 5.691355 | 2.817949 | 1.98064 | 1.648731 | 1.207357 | 0.67522 | 0.476617 |
---|
1
2
| # 각 주성분의 분산
pca.explained_variance_
|
1
2
| array([13.30499079, 5.7013746 , 2.82291016, 1.98412752, 1.65163324,
1.20948224, 0.67640888, 0.47745625])
|
기여율
- 전체 정보량 중 자기 정보량의 비율이다.
- ex) PC1의 기여율 = (13.304990794374552 / 30) = 1.660201
| PC1 | PC2 | PC3 | PC4 | PC5 | PC6 | PC7 | PC8 |
---|
eigenvalue | 0.44272 | 0.189712 | 0.093932 | 0.066021 | 0.054958 | 0.040245 | 0.022507 | 0.015887 |
---|
누적 기여율
- 첫번째 주성분부터 자기 정보량까지 총합의 비율이다.
1
2
| # PC2의 누적 기여율 계산 방법
(eig_value['PC1'] + eig_value['PC2']) / 30
|
1
2
| eigenvalue 0.632432
dtype: float64
|
직접 계산한 결과값과 앞서 계산한 pca_summary와 일치함을 확인할 수 있다.
| Comp1 | Comp2 | Comp3 | Comp4 | Comp5 | Comp6 | Comp7 | Comp8 |
---|
Standard deviation | 3.647601 | 2.387755 | 1.680152 | 1.408591 | 1.285159 | 1.099765 | 0.822441 | 0.690982 |
---|
Propotion of variance | 0.442720 | 0.189712 | 0.093932 | 0.066021 | 0.054958 | 0.040245 | 0.022507 | 0.015887 |
---|
Cumulative proportion | 0.442720 | 0.632432 | 0.726364 | 0.792385 | 0.847343 | 0.887588 | 0.910095 | 0.925983 |
---|