데이터로그😎
PCA (Principal Component Analysis) 본문
차원축소의 대표적인 알고리즘
1. PCA
2. LDA
3. SVD
4. NMF
고차원 데이터의 문제점
- 수백 개 이상의 피처로 구성된 데이터 세트의 경우, 예측 신뢰도가 떨어진다.
- 피처가 많으면 개별 피처 간에 상관관계가 높을 가능성이 큼 → 다중 공선성 문제 발생 → 모델 예측 성능 저하
- 따라서 피처 축소 필요 (차원 축소)
차원축소란?
- 피처 선택, 피처 추출로 나뉨
- 피처 선택(feature selection): 주요 피처만 선택하고 불필요 피처 제거
- 피처 추출(feature extraction): 잠재적 요소 추출.
- ex) 수능성적, 모의고사 성적, 내신성적 => 학업성취도로 요약
- 말그대로 데이터의 차원을 줄이는 것
- 고차원 데이터를 다룰 때 차원의 저주로 인해 모델링이 어려워지고 성능이 저하되는 문제 발생.
- 이를 해결하기 위해 차원축소 실행
- 데이터에서 중요한 특성만 남기고, 노이즈나 불필요한 특성을 제거할 수 있음.
PCA (Principal Component Analysis)
1. 목표
데이터의 평균으로부터 시작해 데이터의 분포를 가장 잘 설명해주는 방향을 찾는 것 (벡터를 찾는 것)
위의 붓꽃 데이터를 예시로 들어보면, 데이터를 가장 잘 설명하는 축을 찾아 정사영(Projection)을 시키면 2차원이었던 데이터를 1차원으로 축소할 수 있다.
2. 결론부터 말하자면..
분포를 가장 잘 설명하는 방향은 분포 분산이 가장 큰 방향이고, 그 다음으로 분포를 잘 설명하는 방향은 첫번째 축에 직교하는 방향이다.
여기서 의문을 가질 수 있다.
Q1. 왜 분산이 가장 큰 방향이 분포를 가장 잘 설명하는가?
Q2. 왜 그 다음으로 잘 설명하는 방향은 첫번째 축에 수직하는가?
이제부터 이 의문을 풀어보자!
Q1. 왜 분산이 가장 큰 방향이 분포를 가장 잘 설명하는가?
https://youtu.be/C21GoH0Y9AE?feature=shared
먼저 original data에서 x,y값 각각의 평균을 빼면 평균은 0이 되어 원점으로 이동하게 된다.
이제 데이터의 분포를 가장 잘 나타내는 축을 찾는 과정에서 Projection을 내렸을 때 데이터-축과의 거리 = 오차이고, 이 오차의 제곱의 평균이 가장 작은 축이 데이터의 분포를 가장 잘 나타내는 축이 된다.
- 주성분 분석 = 주가 되는 성분을 분석한다.
- PCA는 데이터의 고차원 공간에서 *가장 많은 분산을 가지는 방향*을 찾아서 이를 기반으로 데이터를 저차원 공간으로 변환한다.
- PCA에서 '가장 많은 분산을 가지는'은 주어진 데이터셋에서 가장 많은 정보를 가지는 축(axis)을 찾는 것을 의미
- 분산이 커져야 관측치들의 차이점이 더 명확해진다.
- PCA는 데이터셋의 고차원 공간에서 분산이 큰 방향으로 축을 설정하여, 그 방향으로 데이터를 변환한다.이때 분산이 큰 방향이란, 데이터가 퍼져 있는 정도가 가장 큰 방향을 의미한다. 따라서, 이 방향으로 데이터를 변환하면, 데이터의 가장 큰 차원을 가장 잘 보존하면서도, 차원을 축소할 수 있다.
PCA 순서
1. 가장 큰 데이터 변동성(Variance)을 기반으로 첫번째 벡터 축 생성
2. 두번째 축은 이 벡터 축에 직각이 되는 벡터(직교 벡터)를 축으로 함.
3. 세번째 축은 다시 두번째 축과 직각이 되는 벡터를 설정하는 방식으로 축 생성.
선형대수 관점
✅ 공분산 행렬이란?
- 분산 = 한 개의 특정한 변수의 데이터 변동을 의미. 공분산 = 두 변수 간의 변동을 의미
- 키 X, 몸무게 Y → Cov(X, Y) > 0 : 키 X가 증가할 때 몸무게 Y도 증가한다.
- 공분산 행렬 = 여러 변수와 관련된 공분산을 포함하는 정방형 행렬
- 공분산 행렬 = 정방행렬(square matrix) & 대칭행렬(symmetric matrix)
- 정방행렬: 열 수 = 행 수
- 대칭행렬: 대각 원소를 중심으로 원소 값이 대칭되는 행렬. ( Aᵀ = A)
- 대칭행렬은 항상 고유벡터를 직교행렬로, 고유값을 정방행렬로 대각화할 수 있다.
X | Y | Z | |
X | 3.0 | -0.71 | -0.24 |
Y | -0.71 | 4.5 | 0.28 |
Z | -0.24 | 0.28 | 0.91 |
위의 표를 공분산 행렬이라 생각하자.
대각선 원소는 각 변수 X,Y,Z의 분산을 의미하며, 대각선 이외의 원소는 타 변수와의 공분산을 의미한다.
✅ 고유 벡터
- 행렬 A를 곱하더라도 방향이 변하지 않고 크기만 변하는 벡터.
- Ax = ax (A: 행렬, x: 고유벡터, a: 스칼라)
✅ PCA
PCA = 분산행렬!!
(공)분산행렬 = 대칭행렬 (**VᵀV = VVᵀ = I, 따라서 V=V^-1)**→ 대각화 가능(A = V Λ Vᵀ)
- 어떤 데이터의 공분산 행렬=A. 공분산 행렬은 대칭행렬이므로 대각화 식으로 표현 가능 A = V Λ Vᵀ
- 대칭행렬 (**VᵀV = VVᵀ = I, 따라서 V=V^-1)
- A = VΛV^-1
- A: n x n 크기의 정방행렬
- V: A의 고유벡터(eigenvector)들을 열로 쌓아 만든 고유벡터 행렬
- Λ: A의 고유값(eigenvalue)들을 대각원소로 갖는 대각행렬
- V^-1: V의 역행렬
- 여기서 PCA 차원축소가 실행되면 PCA(n_components=2)에 입력된 요소만큼 차원이 축소됨.
- 먼저 V(고유벡터행렬)과 Λ(고유값 행렬)이 내적되며 차원이 축소됨
- V는 가장 큰분산을 가진 고유벡터 순으로 나열되어 있고, Λ(고유값 행렬)의 감마는 고유벡터의 크기임.
실습
from sklearn.datasets import load_iris
import pandas as pd
iris= load_iris()
data = iris.data
feature_names = iris.feature_names
target = iris.target
target_names = iris.target_names
iris_df = pd.DataFrame(
data =data,
columns = feature_names)
iris_df['target'] = target
iris_df.head()
import matplotlib.pyplot as plt
import seaborn as sns
# 꽃잎과 꽃받침을 따로따로 시각화
sepal_columns=[feature_names[0],feature_names[1]]
petal_columns = [feature_names[2],feature_names[3]]
# 꽃받침 시각화
sns.scatterplot(
x=sepal_columns[0],
y=sepal_columns[1],
hue='target',
palette='muted',
data=iris_df)
plt.title('Sepal')
plt.show()
# 0(setosa)는 잘 나뉠 수 있지만, 1과(versicolor) 2(virginica)는 분산이 크지 않음.
# 꽃잎 시각화
sns.scatterplot(
x=petal_columns[0],
y=petal_columns[1],
hue='target',
palette='muted',
data=iris_df)
plt.title('Petal')
plt.show()
- 0: setosa, 1: versicolor, 2:virginica
- setosa의 경우, sepal_width>3.0 & sepal_length < 6.0 인 경우에 일정하게 분포되어 있음.
- versicolor, virginica의 경우 sepal width, length 만으로는 분류가 어려움.
스케일링 & PCA (2차원)
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
iris_scaled = StandardScaler().fit_transform(iris_df.iloc[:,:-1])
pca_2 = PCA(n_components=2)
pca_2.fit(iris_scaled)
# 데이터 변환 수행
iris_pca = pca_2.transform(iris_scaled)
iris_pca.shape # (150,2) --> 2차원으로 축소됨
# PCA로 변환된 데이터를 DataFrame으로 만들기
pca_columns = ['Component 1','Component 2']
iris_pca_df = pd.DataFrame(
data = iris_pca,
columns = pca_columns
)
iris_pca_df['target'] = target
iris_pca_df.head()
PCA 2차원 시각화
sns.scatterplot(
x='Component 1',
y='Component 2',
hue='target',
palette='muted',
data=iris_pca_df)
plt.title('PCA n_component=2')
plt.show()
PCA 변환 후에도 setosa(0)은 여전히 잘 구분됨.
Versicolor, Virginica는 Component1축을 기준으로 겹치는 부분이 있긴 하지만 전에 비해서는 비교적으로 잘 구분됨.
왜? Component1 축이 기존 데이터의 변동성(분산)을 잘 반영하고 있기 때문이다.
아래에서 PCA 개별 컴포넌트 별로 차지하고 있는 변동성 비율을 확인해보자.
PCA 후 설명력
pca_2.explained_variance_ratio_
# 각 주성분의 축을 따라 있는 데이터셋의 분산 비율.
# >>>array([0.72962445, 0.22850762])
- Component1 이 전체 변동성의 73%를,Component2 가 전체 변동성의 23%를 차지
- PCA를 2개 요소로만 변환해도 전체 변동성의 96%를 설명할 수 있다는 말임
- 데이터셋 분산의 73%가 첫번째 주성분을 따라 놓여있고, 23%가 두번째 주성분을 따라 놓여있다는 말임. 세번째 주성분에는 4% 미만이 남아있을 것이라 추정 가능.
PCA (3차원)
pca_3 = PCA(n_components=3)
iris_pca_3 = pca_3.fit_transform(iris_df.drop('target',axis=1))
pca_columns = ['Component 1','Component 2','Component 3']
iris_pca_df = pd.DataFrame(
iris_pca_3,
columns = pca_columns
)
iris_pca_df['target'] = target
PCA 3차원 시각화
color=[]
for n in iris.target:
if n==0:
color.append('r')
elif n==1:
color.append('g')
else:
color.append('b')
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(projection='3d')
colors = ['r', 'g', 'b']
ax.scatter(iris_pca_df['Component 1'], iris_pca_df['Component 2'], iris_pca_df['Component 3'],alpha=0.5, c = color)
이미지, 설명 출처
https://datascienceschool.net/02%20mathematics/03.05%20PCA.html
'머신러닝 > 차원축소' 카테고리의 다른 글
SVD (Singular Value Decomposition) (0) | 2023.09.05 |
---|---|
LDA (Linear Descriminant Analysis) (0) | 2023.09.05 |