들어가며
차원 축소 알고리즘에는 주성분 분석(PCA), 랜덤 투영, 지역 선형 임베딩(LLE) 등이 있다
오늘은 이들 중 주성분 분석(PCA)에 대해 알아볼 것이다
이름만 들었을 때 의미를 유추해보자면 데이터에서 무언가 중요한 성분들을 찾고
이들의 분석을 통해 얻은 정보들로 차원을 축소시키는 느낌 정도로 생각해볼 수 있다
자세한건 아래에서 알아보도록 하겠다
주성분 분석(PCA)
PCA는 데이터 세트의 핵심 정보 중 하나인 분산이 최대로 보존되도록 하는 축(주성분)을 찾아
이들이 생성하는 부분공간에 데이터를 투영시켜 고차원의 데이터 세트를 저차원으로 줄이는 차원 축소 알고리즘이다

왼쪽 그림은 2차원의 데이터셋과 세 개의 축이 각각 실선, 파선, 점선으로 표현되어 있다
오른쪽은 세 개의 축이 데이터의 정보를 얼마나 포함하는 지 각 축에 투영된 결과로 보여준다
세 개의 축 중 분산을 최대로 보존하는 축은 실선 축이고 가장 적게 포함한 것은 점선이다
PCA는 분산이 최대인 축을 찾으니 실선 축을 첫 번째 주성분으로 선택하는 것이 당연하고
두 번째 주성분은 첫번째 축에 직교하면서 남은 분산을 최대로 보존하는 축으로 선택된다
2차원의 데이터셋에서는 직교하는 축이 1개이므로 당연히 점선 축이 선택될 것이다
만약 더 고차원의 데이터였다면 세 번째 주성분은 1,2번째 주성분에 직교하는 축이 선택되고
차원의 수만큼 네 번째, 다섯 번째 ... n번째 주성분이 선택된다
즉 n차원의 데이터는 n개의 주성분을 가진다
하지만 이 n개의 주성분들 중 실제로 의미있는 주성분이 선택되어 차원 축소에 이용된다
주성분(PC) 구하기
어떤 것이 주성분이 되는 건지는 알았는데
훈련 세트를 통해 그 주성분을 어떻게 찾는건지 궁금할 것이다
특잇값 분해(SVD)를 통해 훈련 세트 X를 U Σ Vt 의 세 개의 행렬 곱으로 분해하고
여기서 V에 우리가 찾고자 하는 주성분이 담겨있다
import numpy as np
X_centered = X - X.mean(axis=0)
U, s, Vt = np.linalg.svd(X_centered)
c1 = Vt[0]
c2 = Vt[1]
넘파이의 svd()함수를 이용해 Vt로부터 처음 두 개의 주성분을 추출해내는 코드다
참고로 Vt에는 분산을 최대로 보존하는 축 순서대로 정렬되어 있다
데이터에서 평균을 빼준 이유는 평균을 뺀 값을 입력으로 넣어야
분산의 구조만 파악하기에 알맞게 분해가 된다
분산의 정의 자체가 평균을 기준으로 얼마나 퍼져 있나를 나타낸 값이기 때문이다
부분공간에 데이터 투영시키기
이렇게 주성분을 추출해냈다면 이제는 d개의 주성분들로 만든 부분공간에 데이터를 투영시킬 차례이다
여기서 d는 줄일 차원이 몇차원인지를 나타내는 값이다
d차원에 투영된 데이터셋을 얻기 위해서는 원본 데이터 X와 V의 첫 d열로 구성된 W를 행렬곱셈을 하면된다

코드로 표현하면 아래와 같다
W2 = Vt[:2].T
X2D = X_centered @ W2
이렇게하면 PCA변환이 완료된 것이다
사이킷런에서는 PCA 클래스를 제공하여 아주 간단하게 PCA변환을 할 수 있도록 해준다
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X2D = pca.fit_transform(X)
components_ 안에는 Wd의 전치가 담겨져있다
축소시킬 차원의 수 구하기
그렇다면 우리가 몇차원으로 데이터를 줄일지를 나타내는 d값은 어떻게 구할까?
가장 간단한 방법은 충분한 분산이 될 때까지 주성분의 분산 비율을 더해주면서 차원 수를 결정해주는 것이다
충분한 분산은 95%가 가장 일반적으로 쓰이는 기준이다
주성분의 분산 비율은 사이킷런의 pca.explained_variance_ratio_ 변수를 통해 구할 수 있다
pca.explained_variance_ratio_
array([0.7578477 , 0.15186921])
데이터셋의 차원을 2로 줄이는 PCA의 예시로
첫 번째 주성분은 약 76%의 분산을 담고있고 두 번째 주성분은 15%의 주성분을 담고 있다
차원을 줄이면서 약 9%의 분산이 손실되었다는 의미이기도 하다
우리가 데이터셋을 몇차원으로 줄일지 구할 때 pca.explained_variance_ratio_가 사용된다
from sklearn.datasets import fetch_openml
pca = PCA()
pca.fit(X_train)
cumsum = np.cumsum(pca.explained_variance_ratio_)
d = np.argmax(cumsum >= 0.95) + 1 # d = 154
cumsum() 함수는 누적합을 더해주는 함수로
누적합이 0.95가 넘어가는 첫번째 인덱스+1을 d로 즉 차원의 수(=사용될 주성분의 수)로 할당하는 의미이다
이후 n_components = d로 설정하여 PCA변환을 진행시키면 된다
더 간단한 방법으로는
pca = PCA(n_components=0.95)
X_reduced = pca.fit_transform(X_train)
n_components 값을 0.0 ~ 1.0 사이의 값으로 지정해주면 보존할 분산의 비율로 해석하여
알아서 내부적으로 누적합 계산해주고 적절한 차원 수를 선택해준다
추가로 cumsum() 함수를 그래프로 표현하여 적절한 차원 수를 결정하는 방법도 있다

그래프를 보면 설명된 분산 값의 증가가 줄어드는 변곡점이 있을 것이다
바로 그 지점을 차원 수로 결정하는 것이다
위 그래프에 따르면 차원을 154대신 100으로 해도 분산을 크게 손해보지는 않을 것같다
마치며
이번 글에서는 주성분 변환(PCA)에 대해 알아보았다
책을 통해 개념을 공부하고 있는데
책에서는 데이터를 초평면에 투영시킨다고 PCA를 정의해서 이해하는 데에 약간의 혼란을 겪었다
초평면이라는 것이 수학적으로는 n차원 공간을 나누는 n-1 차원의 평면을 의미하는데
PCA를 할 때 줄일 차원을 무조건 n-1차원으로 정의하지는 않기에 개념 충돌이 일어난 것이다
의문점이 생겨 알아보니 책에서는 아마 초평면을 정보를 보존하면서 안착할 수 있는
최적의 저차원 공간이라고 확장된 의미로 해석했던 것 같다
선형대수학에서는 이를 부분공간(subspace)라고 부른다고 한다
아마 책의 저자분께서는 개념을 이해하기 쉽게 표현을 단순화해서 초평면이라고 써놓지 않았을까하는 생각이 들었다
PCA의 예시로 들 때 n-1차원을 예시로 드는 경우가 많아서 아마 그렇게 한 것 같기도하다
'AI > Machine Learning' 카테고리의 다른 글
| [AI] k-평균 알고리즘 (0) | 2026.05.21 |
|---|---|
| [AI] 존슨-린덴스트라우스 정리를 통한 랜덤 투영, 지역 선형 임베딩(LLE) (0) | 2026.05.07 |
| [AI] AdaBoost, 그레이디언트 부스팅(Gradient Boosting) (0) | 2026.04.30 |
| [AI] 스태킹(Stacking) (1) | 2026.04.25 |
| [AI] 랜덤 패치, 랜덤 서브스페이스, 랜덤 포레스트 (0) | 2026.04.21 |
