PCA는 데이터의 분산(variance)을 최대한 보존하면서 서로 직교하는 새 기저(축)를 찾아, 고차원 공간의 표본들을 선형 연관성이 없는 저차원 공간으로 변환하는 기법입니다.
- Correlated feature를 제거할 수 있습니다.
- 차원 축소된 데이터를 학습데이터로 활용 했을 때 모델의 성능이 좋아집니다. (Overfitting 방지합니다.)
- 시각화하기 용이합니다.
- PCA전 Standardization 필요합니다.
- 정보량 손실이 있습니다.
- Feature의 해석력이 약화됩니다.
- 많은 계산량을 필요로 합니다.
상세코드의 내용을 아래에서 설명합니다.
- 이미지 데이터 로드하기
과일사진 이미지를 아래처럼 로드합니다.
!wget https://bit.ly/fruits_300_data -O fruits_300.npy
import numpy as np
fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)
- PCA를 적용합니다.
아래와 같이 PCA로 50 차원(dimensions)으로 데이터를 축소합니다. 이 경우에 아래처럼 10000이 50으로 축소가 됩니다.
from sklearn.decomposition import PCA
pca = PCA(n_components=50)
pca.fit(fruits_2d)
fruits_pca = pca.transform(fruits_2d)
print(fruits_2d.shape)
print(fruits_pca.shape)
(300, 10000)
(300, 50)
50개의 pca component를 이해를 위해 그려보면 아래와 같습니다.
import matplotlib.pyplot as plt
def draw_fruits(arr, ratio=1):
n = len(arr) # n은 샘플 개수입니다
# 한 줄에 10개씩 이미지를 그립니다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산합니다.
rows = int(np.ceil(n/10))
# 행이 1개 이면 열 개수는 샘플 개수입니다. 그렇지 않으면 10개입니다.
cols = n if rows < 2 else 10
fig, axs = plt.subplots(rows, cols,
figsize=(cols*ratio, rows*ratio), squeeze=False)
for i in range(rows):
for j in range(cols):
if i*10 + j < n: # n 개까지만 그립니다.
axs[i, j].imshow(arr[i*10 + j], cmap='gray_r')
axs[i, j].axis('off')
plt.show()
draw_fruits(pca.components_.reshape(-1, 100, 100))
이때 결과는 아래와 같습니다.
원본으로 재구성 가능한지 아래처럼 시험하면 유사한 원본 이미지를 얻을 수 있습니다.
fruits_inverse = pca.inverse_transform(fruits_pca)
fruits_reconstruct = fruits_inverse.reshape(-1, 100, 100)
for start in [0, 100, 200]:
draw_fruits(fruits_reconstruct[start:start+100])
print("\n")
PCA 적용전의 fruits_2d를 가지고 Logistic regression을 수행한 결과는 정확도는 0.9966666666666667이고, 계산시간은 0.6095898628234864 입니다.
PCA를 이용해 마찬가지로 Logistic Regression을 수행합니다. 아래처럼 계산시간이 개선됨을 알 수 있습니다.
from sklearn.decomposition import PCA
pca = PCA(n_components=50)
pca.fit(fruits_2d)
fruits_pca = pca.transform(fruits_2d)
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
target = np.array([0] * 100 + [1] * 100 + [2] * 100)
from sklearn.model_selection import cross_validate
scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))
1.0
0.03617258071899414
몇 차원까지 축소할것인가를 구하기 위한 예제 코드 입니다.
from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784', version=1, as_frame=False)
mnist.target = mnist.target.astype(np.uint8)
from sklearn.model_selection import train_test_split
X = mnist["data"]
y = mnist["target"]
X_train, X_test, y_train, y_test = train_test_split(X, y)
pca = PCA()
pca.fit(X_train)
cumsum = np.cumsum(pca.explained_variance_ratio_)
d = np.argmax(cumsum >= 0.95) + 1 # 154
print(d) #154
이때의 Elbow는 아래와 같습니다.