코딩뿌셔
차원축소 - 주성분 분석(PCA) 본문
차원축소란?
주성분 분석이란?
대표적인 차원축소 모델로 지도/비지도학습 모두 사용 가능하다.
단독으로 사용하기보다 어떤 모델을 수행하기 위한 소요시간을 줄이기 위해 데이터 차원을 축소하여 적용하는 개념이다.
n_components는 주성분의 갯수를 지정하는 속성으로 모델에서 찾을 주성분 갯수를 의미한다. 이는 클래스 생성시 최초에 무조건 지정해야 한다.
from sklearn.decomposition import PCA
# 클래스(모델) 생성
pca = PCA(n_components = 50)
# 훈련모델 생성
pca.fit(fruits_2d)
# 찾은 주성분 조회
print(pca.components_.shape) # (50, 10000)
import matplotlib.pyplot as plt
def draw_fruits(arr, ratio = 1) :
n=len(arr)
rows = int(np.ceil(n/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 :
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))
print(fruits_2d.shape) # (300, 10000)
차원 축소하기
# 10000개를 50개로
fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape) # (300, 50)
원본 데이터 재구성
# 50개를 다시 10000개로
fruits_inverse = pca.inverse_transform(fruits_pca)
print(fruits_inverse.shape) # (300, 10000)
# 2d > 3d로 변환
fruits_reconstruct = fruits_inverse.reshape(-1,100,100)
print(fruits_reconstruct.shape) # (300, 100, 100)
for start in [0, 100, 200] :
draw_fruits(fruits_reconstruct[start : start+100])
print('\n')
화질은 흐려지고 저하되었지만 잘 나타낸 것을 확인할 수 있다.
KMeans 모델에 차원축소 데이터를 적용하면
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_pca)
print(np.unique(km.labels_, return_counts=True))
# (array([0, 1, 2]), array([111, 98, 91], dtype=int64))
# 클러스터 구성 확인 -> 산점도로 시각화하여 확인
for label in range(0,3) :
data = fruits_pca[km.labels_ == label]
plt.scatter(data[:, 0], data[:, 1])
plt.legend(['apple', 'pineapple', 'banana'])
plt.show()
로지스틱 회귀 모델에 차원축소 데이터 적용해보자. 로지스틱 회귀 모델은 지도학습이기 때문에 타겟값을 만들어 주어야 한다. 행이 300개이므로 타겟도 300개를 만들어 주어야 한다. 이때, 타겟값은 행 자료 특성에 맞도록 사과, 파인애플, 바나나 각 100개씩 0, 1, 2로 생성해준다.
target = [0]*100 + [1]*100 + [2]*100
이해하기 쉽게 눈으로 확인하고 싶다면 데이터프레임화 하여 확인할 수 있다.
df = pd.DataFrame(fruits_2d)
df['target'] = target
df
교차검증으로 성능을 최대화하여 로지스틱회귀 모델에 적용해보면 성능과 훈련 소요시간을 확인할 수 있다.
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_validate
lg = LogisticRegression()
scores = cross_validate(lg, fruits_2d, target)
print(scores)
print(np.mean(scores['test_score'])) # 0.9966666666666667
print(np.mean(scores['fit_time'])) # 0.4458108425140381
훈련에 사용된 독립변수를 차원축소를 적용한 2차원 데이터로 변경하여 로지스틱 회귀 모델을 적용해보자. 이번엔 pca 모델을 생성할 때 n_components를 0.5로 지정한다. 이때, 0.5는 분산비로 분산비율이 50%가 되는동안 계속 찾도록 지정한다는 의미다.
pca = PCA(n_components=0.5)
pca.fit(fruits_2d)
print(pca.n_components_) # 2
# 차원축소
fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape) # (300, 2)
해당 모델이 찾은 주성분의 갯수를 확인해보면 2개로 출력된다. 차원을 축소하면 (300,2) 형태의 2차원 데이터를 얻을 수 있다. 해당 모델로 교차검증을 진행해보자.
scores = cross_validate(lg, fruits_pca, target)
print(scores)
print(np.mean(scores['test_score'])) # 0.9933333333333334
print(np.mean(scores['fit_time'])) # 0.022984743118286133
성능은 거의 동일하게 나타났지만 훈련 소요 시간이 매우 줄어든 것을 확인할 수 있다. 주성분 분석이 성능에는 영향을 미치지 않지만 속도에는 영향을 미친다는 것을 확인할 수 있다. 이에 주성분 분석은 성능은 유지시키되 속도를 향상시키고 싶을 때 사용할 수 있는 모델임을 알 수 있다. 또한, 차원을 축소시킬 수만 있다면 누구든 사용가능한 모델이다.