본문 바로가기
풀스택 개발 학습 과정/머신러닝, 딥러닝

[머신러닝] 비지도 학습 알고리즘 - 주성분분석(공분산행렬) - 1

by 육츠 2023. 11. 26.
Contents 접기

주성분분석 PCA, Principal Component Analysis

주성분분석이란 변수가 가지고 있는 정보의 손실을 최소화 하면서 변수의 차원을 축소하는 분석 기법을 말한다.
여러 변수간에 존재하는 상관관계를 이용하여 이를 대표하는 주성분을 추출해 차원을 축소한다.

차원을 축소해야하는 이유는
- 설명 변수(feature)가 많으면 학습속도가 느려지기 때문이다. 
- 의미 없는 feature 들로 인해 과적합 되거나 학습이 제대로 되지 않는다.
- 차원을 축소하면 데이터를 시각화로 표현하기 쉽다.

* 차원의 저주

차원이 커지면 커질수록 밀도가 낮아진다. 즉 , 공간의 차원이 증가함에 따라 데이터의 밀도가 급격히 감소하고 이로 인해 데이터 분석이나 머신러닝 모델의 성능에 부정적인 영향을 미치는 현상을 말한다.

 

[빅데이터] 차원의 저주(The curse of dimensionality)

차원의 저주란, *데이터 학습을 위해 차원이 증가하면서 학습데이터 수가 차원의 수보다 적어져 성능이 저하되는 현상. *차원이 증가할 수록 개별 차원 내 학습할 데이터 수가 적어지는(sparse) 현

datapedia.tistory.com

 

주성분분석PCA의 원리

- 가장 높은 분산을 가지는(가장 큰 데이터 변동성을 가지는) 데이터의 축을 찾아 이 축으로 차원을 축소한다.
- 분산은 데이터 정보를 설명하는 중요한 통계량이다.
- 주성분은 데이터들의 분산이 가장 큰 방향을 뜻하는 벡터이다.

오른쪽 그림은 좌측의 벡터를 특정벡터에 내적하여 투영한 결과이다.

실선(C1)의 투영은 최대 분산을 유지하고(오른쪽 첫번째 그림), 점선(C2)은 매우 작은 분산만 유지(오른쪽 그림에서 세번째 그림)하고 있다. 따라서, 가장 큰 분산을 유지하는 축을 선택하는 것이 정보 손실이 적기 때문에 C1 축이 첫 번째 주성분이 된다.

그렇다면 어떤 벡터에 내적하는 것이 최적의 결과라고 할 수 있을까? 그것을 해결하기 위해 사용할 수 있는 것이 공분산행렬이다.

 

공분산행렬

두 개 이상의 특성값 사이에서의 변동을 말한다. (분산은 하나의 특성값 사이에서의 변동이다.)
데이터의 구조를 설명해주며 특히 특성간의 변동이 얼마나 닮았는가를 나타내는 행렬이며,
숫자의 크기와 부호를 이용해서 관계의 방향과 크기를 알려준다.

입력데이터의 공분산 행렬이 고유벡터와 고윳값으로 분해될 수 있으며
이렇게 분해된 고유벡터를 이용해 입력데이터를 선형변환 하는 방식이다.

공분산과 상관관계도 연관관계가 있다.

 

[예시] 육상선수 종목별 기록표

어떤 종목을 잘하면 다른 종목도 잘 하는 경향이 있는지. 만약 그렇다면 어떤 종목들이 서로 이러한 경향성에 있어 상대적으로 밀접한 것인지 알 수 없다. 즉, 표 자체로는 데이터의 구조나 경향을 찾기 힘들다.

편차를 구하는 방식은 아래와 같다.

편차 = 각 변량 - 전체 평균
두 편차의 곱이 양인 경우 한 종목에서 평균보다 뛰어나면서 동시에 다른 한 종목에서도 평균보다 뛰어나다는 점을 의미한다.
이러한 두 종목에 대하여 모든 선수들에게 이와 같은 편차들의 곱을 구한 후 이를 평균하는 수식은 다음과 같다.

Cov(X) =  (1 / n - 1) X.T * X

위의 수식을 보면 x가 커질때 y도 함께 커지거나, x가 작아질때 y도 같이 작아지게 되어 곱하게 되면 양수가 된다.
반면, x 가 커질때 y는 작아지거나 x가 작아질때 y가 커지게 되어 곱하면 음수가 된다.  

이 식이 바로 공분산이다. (공분산은 x의 편차와 y의 편차를 곱한것의 평균을 의미한다.)

선수들의 종목별 기록들을 가지고 구한 공분산 행렬은 아래와 같다.

 

공분산 행렬은 정방행렬이며 대칭행렬이다.
대각 성분에는 자기자신의 분산이며 나머지 성분은 서로 다른 두 변수간의 공분산 값이다.

 

[실습] 육상선수 종목별 기록 데이터

데이터 준비

import numpy as np

A = np.array([
              [3.73, 1.86, 15.8, 4.05, 7.27, 45.66, 34.92],
              [3.57, 1.80, 16.23, 2.96, 6.71, 42.56, 37.31],
              [3.22, 1.83, 14.20, 3.51, 6.68, 44.54, 39.23],
              [2.81, 1.80, 15.23, 2.69, 6.25, 42.78, 31.19],
              [2.91, 1.74, 14.76, 2.68, 6.32, 47.46, 35.53],
              [2.67, 1.83, 13.50, 1.96, 6.33, 42.82, 37.64] ])

행: 선수 데이터 / 열: 종목데이터(허들, 높이뛰기,..)

허들 - 높이뛰기 공분산을 구하는 방법
: 첫 선수 허들기록 - (허들기록 평균 값) * 첫 선수 높이뛰기 기록 - (높이뛰기 평균 값) + 두 번째 ... / 6-1

 

허들 종목 통계지표

전에 지수표현 > 실수 3자리 까지 보이도록 설정해놓기

hurdles = A[:,0]
print(hurdles)
print(f'평균: {np.mean(hurdles):.3f}')
print(f'모집단 분산: {np.var(hurdles):.3f}') # 모집단에 대한 분산 (/n)
print(f'불편추정량 분산: {np.var(hurdles,ddof= 1):.3f}') # 불편추정량에 대한 분산 (/n-1)
[3.73 3.57 3.22 2.81 2.91 2.67]
평균: 3.152
모집단 분산: 0.154
불편추정량 분산: 0.184
np.set_printoptions(precision=3, suppress= True)

 

공분산 행렬

#1 np.cov

print('[Covariance Matrix]')
# rowvar : True (기본값)인 경우 행의 변수를 나타내며 열은 각 변수의 관측치를 나타낸다.
# False 일 경우에는 각 행이 관측치(선수 한명당 육상종목별 관측데이터)를 나타내며 열이 변수(종목)를 나타낸다.

B = np.cov(A, rowvar= False)
# print(np.round(B,2))
print(B)
# 정방행렬 ( n x n ) # 대각행렬 = 자기 자신의 분산
[Covariance Matrix]
[[ 0.184  0.007  0.325  0.262  0.151  0.109  0.222]
 [ 0.007  0.002 -0.001  0.014  0.01  -0.029  0.022]
 [ 0.325 -0.001  1.028  0.388  0.199 -0.026 -1.06 ]
 [ 0.262  0.014  0.388  0.528  0.244  0.524  0.078]
 [ 0.151  0.01   0.199  0.244  0.148  0.157  0.21 ]
 [ 0.109 -0.029 -0.026  0.524  0.157  3.884  0.085]
 [ 0.222  0.022 -1.06   0.078  0.21   0.085  7.871]]


# 2 cov = (A.T @ A) / (len(A)-1)

# 종목별 평균
col_mean = np.mean(A, axis = 0)
A = A - col_mean # 표준화

cov = (A.T @ A) / (len(A)-1) # 상응하는 행렬 원소를 곱 :내적: 전치한 데이터 * 원래 데이터
cov
array([[ 0.184,  0.007,  0.325,  0.262,  0.151,  0.109,  0.222],
       [ 0.007,  0.002, -0.001,  0.014,  0.01 , -0.029,  0.022],
       [ 0.325, -0.001,  1.028,  0.388,  0.199, -0.026, -1.06 ],
       [ 0.262,  0.014,  0.388,  0.528,  0.244,  0.524,  0.078],
       [ 0.151,  0.01 ,  0.199,  0.244,  0.148,  0.157,  0.21 ],
       [ 0.109, -0.029, -0.026,  0.524,  0.157,  3.884,  0.085],
       [ 0.222,  0.022, -1.06 ,  0.078,  0.21 ,  0.085,  7.871]])