주성분분석 (PCA)

topics 100-데이터분석 & AI 101 머신러닝 103 데이터 분석,처리
types 이론 실습
tags
references blog.naver.com/prayer2k/222624821291 lets-start-data.tistory.com/entry/%EB... hongl.tistory.com/129

주성분분석 (PCA)

What is PCA?

**주성분분석(Principal Component Analysis, PCA)**은 고차원 데이터를 저차원으로 축소하는 기법이다. 원본 변수들의 선형 결합으로 새로운 축(주성분)을 만들어서, 데이터의 분산을 최대한 보존하면서 차원을 줄인다.

왜 필요한가?

고차원의 저주

  • 변수가 너무 많으면 모델 학습이 느려진다
  • 과적합(Overfitting) 위험이 크다
  • 시각화가 불가능하다 (3차원 이상은 보기 어렵다)

PCA로 해결

  • 중요한 정보는 유지하면서 차원을 줄인다
  • 노이즈를 제거한다
  • 계산 속도가 빨라진다

핵심 아이디어: 데이터의 분산이 큰 방향이 가장 중요한 방향이다. 분산이 작은 방향은 버려도 된다.


PCA vs 랜덤포레스트 변수 중요도

둘 다 변수를 선택하는 방법인데, 뭐가 다를까?

방법 접근 장점 단점
RF Importance 예측 기여도로 선택 해석 쉬움, 직관적 트리 모델에만 특화됨
PCA 분산+노이즈 제거 모든 모델에 적용, 정규화 효과 해석 어려움 (새로운 축 생성)

언제 뭘 쓸까?

  • 해석이 중요하면 → RF Importance
  • 성능이 중요하면 → PCA
  • 둘 다 해보고 비교하는 게 제일 좋다

핵심 개념

PCA가 만드는 주성분이란?

중요: PCA가 뽑은 12개의 주성분은 '특정 칼럼' 자체가 아니다. 원본 칼럼들의 선형 결합(조합)으로 만들어진 새로운 좌표축이다.

예를 들어:

  • 원본 변수: 키, 몸무게, 나이, 연봉
  • 주성분 1: 0.5×키 + 0.3×몸무게 + 0.1×나이 + 0.1×연봉
  • 주성분 2: -0.2×키 + 0.1×몸무게 + 0.6×나이 + 0.1×연봉
  • ...

분산과 공분산

PCA는 데이터의 분산이 가장 큰 방향을 찾는다.

  • 분산(Variance): 데이터가 얼마나 흩어져 있는지
  • 공분산(Covariance): 두 변수가 함께 변하는 정도
  • 상관계수(Correlation): 공분산을 표준화한 것 (-1 ~ 1)

PCA는 공분산 행렬을 이용해서 분산이 최대인 방향을 찾는다.


구현 방법

기본 사용

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# <span id="1-스케일링-필수"></span>1. 스케일링 (필수!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# <span id="2-pca-적용"></span>2. PCA 적용
pca = PCA(n_components=12)  # 12개 주성분
X_pca = pca.fit_transform(X_scaled)

# <span id="3-설명된-분산-비율-확인"></span>3. 설명된 분산 비율 확인
print(f"설명된 분산 비율: {pca.explained_variance_ratio_.sum():.4f}")

왜 스케일링이 필수일까?
변수마다 단위와 범위가 다르면 (예: 키 cm, 연봉 억) PCA가 제대로 작동 안 한다. 표준화로 모든 변수를 같은 스케일로 맞춰야 한다.

n_components 설정 방법

n_components는 2가지 방식으로 설정 가능하다:

1. 주성분 개수로 지정 (정수)

pca = PCA(n_components=12)  # 12개 주성분

2. 분산 비율로 지정 (0~1 실수)

pca = PCA(n_components=0.95)  # 분산 95% 설명하는 만큼

최적 주성분 개수 찾기

여러 개수를 시도해서 비교한다:

n_components_list = [10, 20, 50, 100]
pca_results = {}

for n_components in n_components_list:
    if n_components <= X_scaled.shape[1]:
        pca = PCA(n_components=n_components)
        X_pca = pca.fit_transform(X_scaled)

        explained_variance_ratio = pca.explained_variance_ratio_.sum()
        pca_results[n_components] = {
            'X_pca': X_pca,
            'explained_variance_ratio': explained_variance_ratio,
            'pca': pca
        }

        print(f"PCA {n_components} components: {explained_variance_ratio:.4f} variance explained")

분산 비율로 찾기

print("\n분산 비율별 주성분 개수:")
variance_thresholds = [0.80, 0.85, 0.90, 0.95]

for threshold in variance_thresholds:
    pca = PCA(threshold)
    X_pca = pca.fit_transform(X_scaled)
    print(f"{threshold*100}% 분산: {pca.n_components_}개 주성분")

실행 결과 예시:

80.0% 분산: 15개 주성분
85.0% 분산: 20개 주성분
90.0% 분산: 30개 주성분
95.0% 분산: 45개 주성분

주성분 개수 결정 기준

일반적인 가이드라인:

  • 80~95% 분산: 대부분의 정보를 보존하면서도 차원 축소 효과
  • 95% 이상: 거의 모든 정보 보존, 차원 축소 효과 적음
  • 80% 미만: 너무 많은 정보 손실 위험

최종 결정은 모델 성능으로:

# <span id="여러-주성분-개수로-모델-학습하고-성능-비교"></span>여러 주성분 개수로 모델 학습하고 성능 비교
for n in [10, 20, 30, 50]:
    pca = PCA(n_components=n)
    X_pca = pca.fit_transform(X_scaled)

    model.fit(X_pca, y)
    score = model.score(X_test_pca, y_test)
    print(f"n_components={n}: score={score:.4f}")

장점과 단점

장점

  • 차원 축소로 계산 속도 향상
  • 과적합 방지
  • 노이즈 제거
  • 모든 머신러닝 모델에 적용 가능
  • 다중공선성 문제 해결

단점

  • 해석이 어렵다 (새로운 축은 원본 변수의 조합)
  • 선형 변환만 가능 (비선형 패턴은 못 잡음)
  • 스케일링이 필수 (전처리 필요)
  • 원본 데이터로 복원 시 정보 손실

주의사항

1. 반드시 스케일링 먼저

# <span id="잘못된-예"></span>잘못된 예
pca = PCA(n_components=10)
X_pca = pca.fit_transform(X)  # ❌ 스케일링 안 함

# <span id="올바른-예"></span>올바른 예
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
pca = PCA(n_components=10)
X_pca = pca.fit_transform(X_scaled)  # ✅

2. 테스트 데이터는 transform만

# <span id="학습-데이터"></span>학습 데이터
pca = PCA(n_components=10)
X_train_pca = pca.fit_transform(X_train_scaled)

# <span id="테스트-데이터"></span>테스트 데이터
X_test_pca = pca.transform(X_test_scaled)  # fit 안 함!

관련 문서