이 글은 머신러닝 교과서 with 파이썬, 사이킷런, 텐서플로의 5장 내용을 기반으로 작성되었다.
차원 축소를 하는 이유는 다양하다. 저장 공간을 줄이고 계산 효율을 높이고, 차원의 저주 문제를 감소시키는 등의 역할을 한다. 또한 중요한 특성만을 추출하여 변환 및 투영을 하면 성능이 올라가는 경우가 많다.
차원 선택이 원본 특성을 중요도에 따라 선택한다면,
차원 추출은 새로운 특성 공간으로 데이터를 변환하거나 투영한다.
5.1 PCA
PCA는 주성분 분석을 통해서 비지도 데이터를 선형으로 차원 축소하는 기법이다.
PCA는 작은 차원으로 축소시키는 과정이며 이때 주성분을 선택해야 한다. 주성분은 모든 주성분들이 서로 직교한다는(=상관관계가 없다) 가정 하에 가장 큰 분산을 갖도록 선택한다.
5.1.1 PCA 과정
d차원 -> k차원으로의 PCA의 과정은 다음과 같다.
- d차원 원본 데이터 표준화
- 공분산 행렬 생성
공분산 행렬이란, 두 특성 간의 상관관계를 뜻한다.
수식은 다음과 같다.
여기서 공분산 행렬의 shape은 [d,d]인 square matrix이다. - 공분산 행렬을 고유값, 고유벡터로 분해
고유값은 상수, 고유벡터는 행렬인데 공분산 행렬을 고유값과 고유벡터의 곱으로 나타내는 것이다.
고유값, 고유벡터에 대한 정의는 복잡하고 재미도 없으니 넘어가자 - 고유값을 내림차순으로 정렬 후 가장 높은 k개 선택
- 선택한 k개 고유벡터로 투영행열 W 생성
- 투영행렬 W를 이용해 원본 데이터를 k차원의 새로운 데이터 차원으로 변환
5.1.2 PCA 구현 코드
5.1.2.1 직접 구현
1# 데이터 표준화 2from sklearn.preprocessing import StandardScaler 3 4sc = StandardScaler() 5X_train_std = sc.fit_transform(X_train) 6X_test_std = sc.transform(X_test) 7 8# 공분산 구하고 공분산의 고유값, 고유벡터를 구한다. 9import numpy as np 10cov_mat = np.cov(X_train_std.T) 11eigen_vals, eigen_vecs = np.linalg.eig(cov_mat) 12 13# (고윳값, 고유벡터) 튜플의 리스트를 만듭니다 14eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i]) 15 for i in range(len(eigen_vals))] 16 17# 높은 값에서 낮은 값으로 (고윳값, 고유벡터) 튜플을 정렬합니다 18eigen_pairs.sort(key=lambda k: k[0], reverse=True) 19 20# 여기서는 2개의 특성을 골라서 수평으로 쌓아서 투영행렬 w를 구한다. 21w = np.hstack((eigen_pairs[0][1][:, np.newaxis], 22 eigen_pairs[1][1][:, np.newaxis])) 23 24# 투영행렬 w를 이용해 pca로 차원축소 시키다. 25X_train_pca = X_train_std.dot(w)
5.1.2.2 사이킷런 구현
1from sklearn.decomposition import PCA 2 3# 여기서도 데이터를 표준화시켜야 한다. 4# X_train_std는 표준화된 데이터다. 5 6pca = PCA() 7X_train_pca = pca.fit_transform(X_train_std)
PCA( n_componets=[0~1사이의 값] ) 매게변수를 줄 수 있는데 이는 설명된 분산의 비율을 지정해준 값에 맞게 주성분 개수를 선택한다.
여기서 말하는 (설명된 분산 비율) = 이다.
예를 들어 정렬된 주성분의 설명된 분산 비율이 차례로 0.4, 0.3, 0.2, 0.1 일때
n_components = 0.9이라면 [0.4, 0.3, 0.2]인 주성분을 선택한다.
5.2 LDA
LDA는 지도 데이터를 선형으로 차원 축소하는 기법이다.
- PCA가 전체 데이터의 분산이 최대가 되도록 주성분을 설정한다고 한다면,
- LDA는 클래스 간 분산(between-class variance)과 클래스 내 분산(within-class variance)을 최대화하고 최소화하려고 노력한다.
이렇게 하면 서로 다른 클래스 간의 거리가 최대화되며, 같은 클래스 내의 데이터 포인트 간의 거리는 최소화된다.
참고로 LDA가 좀 더 분류에 최적화되어 있다고 한다.
그럼 이제 LDA의 과정과 구현을 알아보자.
5.2.1 LDA 과정
d차원의 원본데이터를 k차원의 데이터로 LDA 차원축소한다고 하자.
- 원본 데이터 표준화
- 각 클래스에 대해 d차원의(=특성 d개에 대한) 평균벡터 계산
- 클래스 간 산포행렬 와 클래스 내 산포행렬 를 계산
산포행렬이란 데이터들 간의 분산과 공분산을 나타내는다. 이를 통해 데이터 분포를 알 수 있다.
수식은 다음과 같다.
, (여기서 는 평균벡터다.)