주성분 분석(PCA)를 이용해 통계적으로 독립인 데이터로 만드는 방법
선형대수학에서 배운 PCA 를 통해 데이터를 통계적으로 독립인 데이터로 전처리하는 방법을 배워본다. 먼저 통계적으로 독립인 전처리를 수행하는 PCA를 수식으로 표현 후 실제 예제 데이터를 사용해 코드로 적용해본다.
PCA 전처리 수식전개
는
설계행렬이라 두고
가 되어있는 즉, 자료의 평균은 0이라고 가정한다.(각 특성에 각 특성평균을 빼준 것).
와 관련된 불편 표본 공분산 행렬은 다음과 같이 주어진다.
PCA 전처리를 하는 최종적인 목적은 를 선형변환을 통해 찾는 것이다. (
는 대각행렬이다.)
설계행렬 의 주성분은
의 고유벡터이며 대칭행렬로써 다음과 같이 분해가 가능하다.
(
:
값에 차례대로 대응하는 고유벡터.
: 고윳값.)
위의 분해는 대칭행렬에 대한 특별한 성질을 만족하는 분해 표현이다. 위의 방법을 통해서 쉽게 유도할 수 있지만 일반적인 분해방법인 SVD(특이값 분해)를 사용하여 유도해보면 다음과 같다. (:
좌특이 벡터,
:
우특이 벡터)
(
는 모두 직교행렬이다.)
위 식으로 를 유도하면 다음과 같다.
직교행렬이기 때문에 가 성립한다. 이제
를 유도하려면
를 없애는 선형변환을 시켜줘야한다.
를 이용하여 다음과 같이 유도할 수 있다.
(
직교행렬)
정리하자면 자료 를 선형변환
를 통해
에 투영한 결과로 얻은 표현의 공분산행렬
은 하나의 대각행렬이다. 따라서
의 성분들 사이에는 상관관계가 존재하지 않는다.
예제를 사용한 구현
위의 PCA를 사용한 통계적으로 독립인 데이터를 만드는 방법을 코드로 구현해본다. 사용할 데이터는 keras.dataset 에서 제공하는 boston_housing dataset을 사용한다.
|
1 2 3 4 5 6 7 8 |
import numpy as np from keras.datasets import boston_housing (x_train, y_train),(x_test, y_test) = boston_housing.load_data() print(x_train.shape) print(y_train.shape) print(x_test.shape) print(y_test.shape) |
boston_housing dataset에는 404개의 훈련 데이터(13개의 특성을 가진) 와 102개의 테스트 데이터가 있다.

여기서 x_train 데이터만 사용하여 구현해본다. 먼저 x_train 데이터하나의 구성을 본다.
|
1 |
print(x_train[0]) |
![]()
13가지 특성을 가지고 있는데 수치를 보면 표준화가 되어있지 않아 표준화를 해준다.
|
1 2 3 4 |
x_train_mean = np.average(x_train, axis=0) # 데이터 X = X - E[X] 표준화 x_train = x_train - x_train_mean print(np.average(x_train,axis=0)) |

변환된 x_train 의 평균을 보면 0인 것을 볼 수 있다. (잘 변환 됨.)
변환된 x_train을 로 변환하여
[x_train] 을 구한다. (
로 나누는 작업은 하지 않음.)
|
1 2 |
pca_x_data = np.dot(np.transpose(x_train),x_train) print(pca_x_data.shape) |
변환된 pca_x_data.shape 의 형태는
과 같다. 이제 변환된 를 SVD 로 분해하여
를 구한다.
|
1 |
W,A,W_T = np.linalg.svd(pca_x_data) |
구한 를 통해
를 구하고
를 구한다.
|
1 2 |
Z = np.dot(x_train,W) Z_T_Z = np.dot(np.transpose(Z),Z) |
이렇게 구한 는
인 대각행렬임을 나타내고 잘 변환이 되어있다면
의 대각행렬의 합은
행렬의 모든 요소의 합과 같을 것이다. 이를 확인해본다.
|
1 2 3 4 5 6 |
sum_diag = 0 for i in range(13): sum_diag += Z_T_Z[i,i] print("대각행렬 Z[i,i]의 합:",sum_diag) print("두 행렬의 차이 : ",np.sum(Z_T_Z) - sum_diag) |
![]()
마지막으로 을 구하면 다음과 같다.
|
1 2 |
Z_T_Z_result = Z_T_Z / 403. print(np.sum(Z_T_Z_result)) |
![]()
References : 심층학습