차원 축소
차원의 저주는 n x p 일때 p가 많은 경우, 연산이 어렵고 데이터 표현이 어려움
이를 위해 차원을 축소함 차원 축소로 인해 정보 손실이 발생할 수 있음
예시)
국어: 80점, 영어 60점, 수학 90점, 과학 90점
평균 = (80+60+90+80)/4 = 77.5점
평균이라는 하나의 차원으로 나타냄, 하지만 평균으로 각 과목의 점수가 몇인지는 정확히 알 수 없음.
정보 손실을 최소화하는 것이 관건.
pc1 축으로 하면 좌표들이 겹치지 않고 정보를 가져올 수 있음.
축에 영세했을 때 가장 많이 퍼져있는 것을 알 수 있음. 축을 찾아내는 과정이 주성분 분석이라고 할 수 있다.
주성분 분석
고차원 데이터를 저차원 데이터로 환원한다.
분산이 가장 커질때 (= 정보 손실을 최소화 하는)축을 pc1, 그 다음으로 커지는 것을 pc2로 설정하여 데이터를 선형 변환함.
pc1 : 분산이 가장 큰 (넓게 퍼져있는) 방향을 구하여 축을 구함
pc2 : pc1과 직교하면서 + 분산이 두번째로 큰 방향
주성분 분석 절차
데이터 표준화 (평균0, 표준편차 1) -> 분산도가 큰 방향을 찾아서 pc1 생성 -> 구해진 주성분 축으로 좌표 변환
2차원 분류를 1차원으로 축소 시
C영역이 겹침, 정보손실을 최소화 하여 주성분 축을 찾았을 때 c영역이 줄어든 것을 알 수 있음
3차원 데이터를 2차원으로 축소
분산도 높게 펼칠 수 있는 2차원 평면 생성
code
import pandas as pd
# Eating, exercise habbit and their body shape
df = pd.DataFrame(columns=['calory', 'breakfast', 'lunch', 'dinner', 'exercise', 'body_shape'])
df.loc[0] = [1200, 1, 0, 0, 2, 'Skinny']
df.loc[1] = [2800, 1, 1, 1, 1, 'Normal']
df.loc[2] = [3500, 2, 2, 1, 0, 'Fat']
df.loc[3] = [1400, 0, 1, 0, 3, 'Skinny']
df.loc[4] = [5000, 2, 2, 2, 0, 'Fat']
df.loc[5] = [1300, 0, 0, 1, 2, 'Skinny']
df.loc[6] = [3000, 1, 0, 1, 1, 'Normal']
df.loc[7] = [4000, 2, 2, 2, 0, 'Fat']
df.loc[8] = [2600, 0, 2, 0, 0, 'Normal']
df.loc[9] = [3000, 1, 2, 1, 1, 'Fat']
df.head()
#고차원 데이터 축소
#벡터 추출
X = df[['calory','breakfast','lunch','dinner','exercise']]
X. head()
Y = df[['body_shape']]
Y.head()
#벡터 표준화
from sklearn.preprocessing import StandardScaler #정규분포 하에 표준화
x_std = StandardScaler().fit_transform(X)
x_std
array([[-1.35205803, 0. , -1.3764944 , -1.28571429, 1. ],
[ 0.01711466, 0. , -0.22941573, 0.14285714, 0. ],
[ 0.61612771, 1.29099445, 0.91766294, 0.14285714, -1. ],
[-1.18091145, -1.29099445, -0.22941573, -1.28571429, 2. ],
[ 1.89972711, 1.29099445, 0.91766294, 1.57142857, -1. ],
[-1.26648474, -1.29099445, -1.3764944 , 0.14285714, 1. ],
[ 0.18826125, 0. , -1.3764944 , 0.14285714, 0. ],
[ 1.04399418, 1.29099445, 0.91766294, 1.57142857, -1. ],
[-0.15403193, -1.29099445, 0.91766294, -1.28571429, -1. ],
[ 0.18826125, 0. , 0.91766294, 0.14285714, 0. ]])
print(x_std.mean()) #평균 0
print(x_std.std()) # 표준편차 1
3.552713678800501e-17
1.0
x_std.T
array([[-1.35205803, 0.01711466, 0.61612771, -1.18091145, 1.89972711,
-1.26648474, 0.18826125, 1.04399418, -0.15403193, 0.18826125],
[ 0. , 0. , 1.29099445, -1.29099445, 1.29099445,
-1.29099445, 0. , 1.29099445, -1.29099445, 0. ],
[-1.3764944 , -0.22941573, 0.91766294, -0.22941573, 0.91766294,
-1.3764944 , -1.3764944 , 0.91766294, 0.91766294, 0.91766294],
[-1.28571429, 0.14285714, 0.14285714, -1.28571429, 1.57142857,
0.14285714, 0.14285714, 1.57142857, -1.28571429, 0.14285714],
[ 1. , 0. , -1. , 2. , -1. ,
1. , 0. , -1. , -1. , 0. ]])
#공분산 행렬 분산 -> 주성분 축 찾기
import numpy as np
features = x_std.T
covariance_matrix = np.cov(features)
print(covariance_matrix)
[[ 1.11111111 0.88379717 0.76782385 0.89376551 -0.93179808]
[ 0.88379717 1.11111111 0.49362406 0.81967902 -0.71721914]
[ 0.76782385 0.49362406 1.11111111 0.40056715 -0.76471911]
[ 0.89376551 0.81967902 0.40056715 1.11111111 -0.63492063]
[-0.93179808 -0.71721914 -0.76471911 -0.63492063 1.11111111]]
x_std.T.dot(x_std)/9 #dot은 두 array의 내적을 계산함 (행렬곱)
#표준화 데이터 .T * x_std 내적 / 샘플의수 = 넘파이의 공분산 행렬과 동일함
array([[ 1.11111111, 0.88379717, 0.76782385, 0.89376551, -0.93179808],
[ 0.88379717, 1.11111111, 0.49362406, 0.81967902, -0.71721914],
[ 0.76782385, 0.49362406, 1.11111111, 0.40056715, -0.76471911],
[ 0.89376551, 0.81967902, 0.40056715, 1.11111111, -0.63492063],
[-0.93179808, -0.71721914, -0.76471911, -0.63492063, 1.11111111]])
#고유벡터/ 고유값 산출
eig_vals, eig_vecs = np.linalg.eig(covariance_matrix)
print('Eigenvalues \n%s' %eig_vals) #축 별 정보의 양
print('Eigenvectors \n%s' %eig_vecs) #주성분 축
Eigenvalues
[4.0657343 0.8387565 0.07629538 0.27758568 0.2971837 ]
Eigenvectors
[[-0.508005 -0.0169937 -0.84711404 0.11637853 0.10244985]
[-0.44660335 -0.36890361 0.12808055 -0.63112016 -0.49973822]
[-0.38377913 0.70804084 0.20681005 -0.40305226 0.38232213]
[-0.42845209 -0.53194699 0.3694462 0.22228235 0.58954327]
[ 0.46002038 -0.2816592 -0.29450345 -0.61341895 0.49601841]]
# 1개 차원으로 축소했을때 73%의 정보를 보유
eig_vals[0] / sum(eig_vals) #첫번째 축/ 전체의 합 = 73%
0.7318321731427544
#분해한 데이터를 1차원에 투영
eig_vecs.T[0]
array([-0.508005 , -0.44660335, -0.38377913, -0.42845209, 0.46002038])
# 첫번쨰 축정보 첫번째 표준화 데이터 내적 계산
projected_X = x_std.dot(eig_vecs.T[0])
projected_X #처음 데이터를 1차원으로 투영
array([ 2.22600943, 0.0181432 , -1.76296611, 2.73542407, -3.02711544,
2.14702579, 0.37142473, -2.59239883, 0.39347815, -0.50902498])
result = pd.DataFrame(projected_X, columns=['PC1'])
result['y-axis'] = 0.0
result['label'] = Y
result
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.lmplot(x='PC1',y='y-axis',data= result, fit_reg=False,
scatter_kws={"s": 50},
hue = "label")
# title
plt.title('PCA result')
#데이터가 skinny 부분에서 겹침 분산이 가장 넓은 주성분 축을 찾아서 투영했기 때문에 정보손실이 최소화 하면서 차원축소함
'Deep Learning > NLP' 카테고리의 다른 글
10. TextRank (0) | 2023.03.28 |
---|---|
09. 핵심키워드 추출 (0) | 2023.03.25 |
07. TF-IDF(단어빈도-역문서빈도) (0) | 2023.03.18 |
06. Bag of Words, TDM (0) | 2023.03.17 |
05. TF-IDF, N-gram (0) | 2023.03.13 |