본문 바로가기
컴퓨터공학/AI

기계 학습 8. 차원 축소(Dimensionality Reduction)

by Jinger 2023. 10. 28.

서론

    많은 머신러닝 문제는 각 훈련 인스턴스마다 수천 또는 수백만 개의 특성을 포함한다. 이러한 모든 특성은 훈련을 극도로 느리게 만들뿐만 아니라 좋은 해결책을 찾기도 훨씬 어렵게 만들 수 있다. 이 문제는 차원의 저주(curse of dimensionality)로 불린다. 다행히 현실 세계의 문제에서는 특성의 수를 상당히 줄일 수 있으며, 이는 처리 불가능한 문제를 처리 가능한 문제로 바꿀 수 있다. 차원 축소는 훈련 속도를 높이는 데 도움이 되는 것 외에도 데이터 시각화(DataViz)에 극도로 유용하다.


The Curse of Dimensionality

    차원의 저주(The Curse of Dimensionality)란 고차원 공간에서 일어나는 다양한 현상들을 설명한다. 인간은 3차원까지 볼 수 있는 존재이므로 그 이상의 차원은 상상하기 어렵다. 그러나 수학적으로 고차원 공간에서는 무작위로 선택한 점이 경계에 가까이 있을 확률이 매우 높아지며, 두 점 간의 평균 거리가 기하급수적으로 증가하는 특징이 있다. 또한 고차원 데이터셋은 희소성 문제를 안고 있어서 훈련 인스턴스 간의 거리가 멀어져 예측이 부정확해질 수 있다. 차원의 저주를 해결하기 위해서는 훈련 세트의 크기를 증가시키는 방법이 이론적으로 가능하지만, 실제로는 필요한 훈련 인스턴스 수가 기하급수적으로 증가하기 때문에 효과적이지 않다.


Main Approached for Dimensionality Reduction

Projection(투영, 투사)

Projection

    프로젝션(Projection)은 고차원 데이터셋을 저차원 부분 공간으로 투영하는 방법 중 하나이다. 실제로 대부분의 실제 문제에서는 특성들이 거의 일정하거나 강하게 상관관계를 가지는 경우가 많다. 이로 인해 모든 훈련 인스턴스는 고차원 공간의 훨씬 낮은 차원의 부분 공간 내에 존재하거나 가깝게 위치한다. 그러나 프로젝션은 차원 축소를 위한 최상의 접근 방법이라고 할 수는 없다. 많은 경우 부분 공간이 꼬여 있거나 구부러진 경우가 있으며, 이를 고려하지 않고 단순히 평면으로 투영할 경우 데이터셋이 왜곡될 수 있다.

Manifold Learning

Swiss roll

    매니폴드 학습(Manifold Learning)은 고차원 데이터셋이 근접한 저차원 매니폴드에 가깝게 위치하고 있다는 가정에 기초한 차원 축소 알고리즘이다. 이는 데이터셋이 국소적으로 d차원 초평면과 유사한 n차원 공간(즉, d < n)에 위치한다는 것을 의미한다. 매니폴드 가정(manifold assumption, manifold hypothesis)은 현실 세계의 대부분의 고차원 데이터셋이 훨씬 낮은 차원의 매니폴드에 가깝게 위치한다는 것을 가정한다. 이러한 매니폴드 공간에서 표현된다면 분류나 회귀와 같은 작업이 더 간단해질 것으로 차원을 축소시킨다. 그러나 이러한 내제적 가정은 항상 성립하는 것은 아니다. 따라서 모델의 훈련을 위해 차원을 축소하는 것은 보통 훈련을 가속화할 수 있지만, 항상 더 나은 또는 더 간단한 솔루션으로 이어지는 것은 아닐 수 있다.


Principal Component Analysis (PCA)

분산 보존(Preserving the Variance)

    분산 보존PCA(Principal Component Analysis)의 핵심 원리 중 하나이다. PCA는 가장 인기 있는 차원 축소 알고리즘 중 하나로, 먼저 데이터에 가장 가까운 초평면을 찾고, 그 다음 데이터를 해당 초평면에 투영한다. 데이터셋을 저차원 초평면에 투영하기 전에 적절한 초평면을 선택해야 한다. 최대 분산을 보존하는 축을 선택하는 것이 합리적으로 보이며, 이는 다른 투영에 비해 더 적은 정보를 잃을 가능성이 높다. 또 다른 이 선택을 정당화하는 방법은 원래 데이터셋과 해당 축에 대한 투영 간의 평균 제곱 거리를 최소화하는 축이기도 한다.

Principal Components

    주성분(Principal Components)은 주어진 학습 데이터셋에서 가장 큰 분산을 설명하는 축을 식별한다. 예를 들어 위 그림에서는 c1 축이 mass를 나타내는 solid line 이다. 또한 첫 번째 축과 직교하는 두 번째 축도 찾아 해당 축에 남은 분산의 큰 부분을 설명한다. 이러한 주성분(PC)은 데이터의 주축이라고 할 수 있다. 예를 들어 위 그림에서 첫 번째 PC는 벡터 c1이 위치한 축이고, 두 번째 PC는 벡터 c2가 위치한 축이다. 마찬가지로 우측 그림에서 첫 번째 두 PC는 평면 상의 두 화살표가 위치한 직교하는 축이며, 세 번째 PC는 해당 평면과 직교하는 축이다. 주성분을 찾기 위해서는 표준 행렬 분해 기법인 특잇값 분해(SVD)라는 방법을 사용한다. 이를 통해 학습 데이터셋 행렬 X를 U Σ VT라는 세 행렬의 곱으로 분해할 수 있으며, 여기서 V는 우리가 찾는 모든 주성분을 정의하는 단위 벡터를 포함한다. 따라서 numpy를 사용하여 첫 번째 두 주성분을 정의하는 두 단위 벡터를 추출할 수 있다. PCA는 데이터셋이 원점을 중심으로 한다는 가정을 전제로 한다.

Projecting Down to d Dimensions(d 차원까지 투영)

# PCA 간단 로직
X_centered = X - X.mean(axis = 0)
U, s, Vt = np.linalg.svd(X_centered)
c1 = Vt.T[:, 0]
c2 = Vt.T[:, 1]

W2 = Vt.T[:, :2]
X2D = X_centered.dot(W2)

# Scikit-Learn's PCA
from sklearn.decomposition import PCA

pca = PCA(n_components = 2)
X2D = pca.fit_transform(X)

pca.explained_variance_ratio_	# array([0.84248607, 0.14631839])

   모든 주성분을 식별한 후, 첫 d개의 주성분이 정의하는 초평면에 데이터셋을 투영하여 데이터셋의 차원을 d로 축소할 수 있다. 학습 데이터셋을 초평면에 투영하여 차원이 d인 축소된 데이터셋 X_d-proj를 얻으려면, 학습 데이터셋 행렬 X와 V의 첫 d개 열을 포함하는 행렬 Wd의 행렬 곱셈을 계산하면 된다(위 식 참조). Scikit-Learn의 PCA 클래스를 사용할 수 있다.
    또 다른 유용한 정보는 각 주성분의 설명된 분산 비율이다. explained_variance_ratio_ 변수를 통해 사용할 수 있다. 이 비율은 각 주성분을 따라 있는 데이터셋의 분산의 비율을 나타낸다. 예를 들어, Figure 8-2에 나타난 3차원 데이터셋의 처음 두 성분의 설명된 분산 비율을 살펴보자. 이 출력 결과는 데이터셋 분산의 84.2%가 첫 번째 PC를 따라 있고, 14.6%가 두 번째 PC를 따라 간다고 알려준다. 이는 세 번째 PC에는 1.2% 미만의 정보가 포함되어 있으므로 세 번째 PC는 거의 정보를 포함하지 않을 것으로 생각할 수 있다.

Choosing the Right Number of Dimensions(올바른 차원 수 선택)

pca = PCA()
pca.fit(X_train)
cumsum = np.cumsum(pca.explain_variance_ratio_)
d = np.argmax(cumsum >= 0.95) + 1

pca = PCA(n_components = 0.95)
X_reduced = pca.fit_transform(X_train)

    올바른 차원 수를 선택하는 것은 무작위로 차원을 줄이는 것보다 분산의 충분히 큰 부분을 더하는 차원 수를 선택하는 것이 더 간단하다(예: 95%). 그런 다음 n_components를 d로 설정하고 다시 PCA를 실행할 수 있다. 그러나 훨씬 더 나은 옵션이 있다. 보존할 주성분 수를 지정하는 대신 n_components를 0.0과 1.0 사이의 부동 소수점으로 설정하여 보존할 분산의 비율을 나타낼 수 있다. 또 다른 옵션은 차원 수에 따른 설명된 분산을 그래프로 나타내는 것이다(단순히 누적 합을 그래프로 표시하면 됩니다; Figure 8-8을 참조). 일반적으로 설명된 분산이 빠르게 증가하는 지점에 팔꿈치(Elbow)가 있을 것이다.

PCA for Compression(압축을 위한 PCA)

pca = PCA(n_components = 154)
X_reduced = pca.fit_transform(X_train)
X_recovered = pca.inverse_transform(X_reduced)

    차원 축소 후 훈련 세트는 훨씬 적은 용량을 차지한다. 예를 들어 MNIST 데이터 세트에 PCA를 적용하여 분산의 95%를 보존하는 동안 각 인스턴스는 원래 784(28x28) 특성의 20% 이상인 150개가 조금 넘는 특성을 가진다고 하자. 이것은 합리적인 압축 비율이며 이러한 크기 감소가 분류 알고리즘을 엄청나게 가속화할 수 있는 방법이 있다. 축소된 데이터 세트를 PCA 투영의 역변환을 적용하여 784 차원으로 다시 압축 해제할 수도 있다. 단, 이는 원본 데이터를 반환하지는 않는다(누락된 5% 분산 내에서), 하지만 원본 데이터와 거의 비슷할 것이다. 원본 데이터와 재구성된 데이터(압축 및 다시 압축) 간의 평균 제곱 거리를 재구성 오류라고 한다. 다음 코드는 MNIST 데이터 세트를 154 차원으로 압축하고, inverse_transform() 메서드를 사용하여 다시 784 차원으로 복원한다. (역변환의 방정식은 𝐖𝑑: 직교 행렬, 즉 𝐖𝑑𝐖𝑑T = I이다.)

Randomized PCA

    만약 svd_solver 하이퍼파라미터를 "randomized"로 설정하면, Scikit-Learn은 Randomized PCA라는 확률적 알고리즘을 사용하여 첫 d개의 주성분의 근사치를 빠르게 찾을 수 있다. 계산 복잡도는 전체 SVD 방법의 𝑂(𝑚 × 𝑑²) + 𝑂(𝑑³) 대신에 𝑂(𝑚 × 𝑛²) + 𝑂(𝑛³)이다. 따라서 𝑑이 𝑛보다 훨씬 작을 때 전체 SVD보다 훨씬 빠르다. 실제로 svd_solver는 기본적으로 "auto"로 설정되어 있다. Scikit-Learn은 자동으로 randomized PCA 알고리즘을 사용한다. 만약 𝑚 또는 𝑛이 500보다 크고 𝑑가 𝑚 또는 𝑛의 80%보다 작은 경우에는 전체 SVD 방법을 사용한다.

Incremental PCA

from sklearn.decomposition import IncrementalPCA

n_batched = 100
inc_pca = IncrementalPCA(X_train, n_batches):
	inc_pca.partial_fit(X_batch)
    
X_reduced = inc_pca.transform(X_train)

    이전의 PCA 구현 방식들은 알고리즘이 실행되려면 전체 훈련 세트가 메모리에 맞아야 한다는 문제가 있다. 이를 해결하기 위해 점진적 PCA(Incremental PCA, IPCA) 알고리즘이 개발되었다. 이 알고리즘들은 훈련 세트를 미니배치로 나누고 IPCA 알고리즘에 하나의 미니배치씩 공급할 수 있도록 한다.

Kernel PCA

from sklearn.decomposition import KernelPCA

rbf_pca = KernelPCA(n_components = 2, kernel = "rbf", gamma = 0.04)
X_reduced = rbf_pca.fit_transform(X)

   이전 블로그에 이야기했던 커널 트릭은 인스턴스를 암묵적으로 매우 고차원 공간(특성 공간이라고 함)으로 매핑하여 서포트 벡터 머신을 사용한 비선형 분류 및 회귀를 가능하게 하는 수학적 기술이다. 고차원 특성 공간에서의 선형 결정 경계는 원래 공간에서 복잡한 비선형 결정 경계에 해당한다는 것을 기억해보자. 마찬가지로 동일한 기술을 PCA에 적용하여 차원 축소를 위한 복잡한 비선형 투영을 수행할 수 있다. 이를 커널 PCA(kPCA)라고 한다. kPCA는 종종 투영 후 인스턴스 클러스터를 보존하거나 때로는 비틀린 다양체에 가까이 있는 데이터셋을 풀어내는 데 효과적이다. Scikit-Learn의 KernelPCA 클래스를 사용하여 RBF 커널로 kPCA를 수행할 수 있다.

Selecting a Kernel and Tuning Hyperparameters(커널 선택 및 초매개변수 조정)

from sklearn.model_selection import GridSearchCV
from sklearn.liner_model import LogisticRegression
from sklearn.pipeline import Pipeline

clf = Pipeline([
   ("kpca", KernelPCA(n_components = 2)),
   ("log_reg", LogisticRegression())
])

param_grid = [{
   "kcpa__gamma": np.linspace(0.03, 0.05, 10),
   "kcpa_kernel": ["rbf", "sigmoid"]
}]

grid_search = GridSearchCV(clf, param_gird, cv = 3)
grid_search.fit(X, y)

print(grid_search.best_params_)	#{kpca_gamma : 0.04333333333, kcpa_kernel : rbf}

rbf_pca = KernelPCA(n_components = 2, kernel = "rbf", gamma = 0.0433, fit_inverse_trandform=True)
X_reduced = rbf_pca.fit_transform(X)
X_preimage = rbf_pca.inverse_transform(X_reduced)

from sklearn.metrics import mean_squared_error
mean_squared_error(X, X_preimage)	# 32.786308795766132

    커널을 선택하고 하이퍼파라미터를 조정하는 것은 kPCA가 비지도 학습 알고리즘이기 때문에 가장 좋은 커널과 하이퍼파라미터 값을 선택하는 데 도움이 되는 명백한 성능 측정 지표가 없다. 차원 축소는 종종 지도 학습 작업(예: 분류)의 준비 단계이므로 그 작업에서 최상의 성능을 내는 커널과 하이퍼파라미터를 선택하기 위해 그리드 서치를 사용할 수 있다. 먼저 kPCA를 사용하여 차원을 두 개로 축소한 후 분류를 위해 Logistic Regression을 적용하는 두 단계 파이프라인을 만든 다음, 파이프라인 끝에서 최상의 분류 정확도를 얻기 위해 kPCA에 대한 최적의 커널과 감마 값을 찾기 위해 GridSearchCV를 사용한다. 다른 방법으로는 완전히 비지도 방식으로 재구성 오차가 가장 낮은 커널과 하이퍼파라미터를 선택하는 것이다. 선형 PCA와는 달리 재구성이 그렇게 간단하지는 않음을 기억하자. 커널 트릭 덕분에 이 변환은 수학적으로 봤을 때 훈련 세트를 무한 차원의 특성 공간으로 매핑한 다음, 선형 PCA를 사용하여 변환된 훈련 세트를 2D로 투영하는 것과 동일하다. 특성 공간이 무한 차원이므로 재구성된 점을 계산할 수 없으므로 진짜 재구성 오차를 계산할 수 없다. 다행히도, 재구성된 점에 가까이 매핑될 수 있는 원래 공간의 점을 찾을 수 있다. 이 점을 재구성 사전 이미지라고 한다. fit_inverse_transform=True로 설정하면 Scikit-Learn이 이를 자동으로 수행한다.

Locally Linear Embedding (LLE)

from sklearn.manifold import LocallyLinearEmedding

lle = LocallyLinearEmbedding(n_components=2, n_neighbors = 10)
X_reduced = lle.fit_transform(X)

    로컬리 선형 임베딩(Locally Linear Embedding, LLE)은 또 다른 강력한 비선형 차원 축소(NLDR) 기술입니다. 이는 이전 알고리즘들과 달리 프로젝션에 의존하지 않는 매니폴드 학습 기술입니다. LLE는 먼저 각 훈련 인스턴스가 가장 가까운 이웃(들)과 선형적으로 어떻게 관련되는지 측정한 다음, 이러한 지역적 관계가 가장 잘 보존되는 훈련 세트의 저차원 표현을 찾는 알고림즘이다. 이 접근 방식은 특히 뒤틀린 매니폴드를 펼치는 데 효과적이며, 특히 너무 많은 노이즈가 없는 경우에 효과적입니다.

LLE 작동 방식

   로컬리 선형 임베딩(LLE)는 다음과 같은 방식으로 작동한다. 각 훈련 인스턴스 𝐱𝑖에 대해 알고리즘은 먼저 가장 가까운 이웃과의 선형 관계를 측정한 다음, 이러한 지역 관계가 가장 잘 보존되는 낮은 차원 표현을 찾는다. 이 접근 방식은 특히 뒤틀린 다양체를 펼치는 데 유용하다. 이 단계를 통해 가중치 행렬 𝐖(𝑤𝑖,𝑗 가중치 포함)은 훈련 인스턴스 간의 지역 선형 관계를 인코딩한다. 이후, 이러한 지역 관계를 최대한 보존하면서 훈련 인스턴스를 𝑑 차원 공간(여기서 𝑑 < 𝑛)으로 매핑한다. 이때, 각 훈련 인스턴스의 이미지인 𝐳 𝑖와 ∑𝑗=1 𝑚𝑤𝑖,𝑗𝐳 𝑗 간의 제곱 거리가 가능한 한 작아지도록 하다.(z가 작아지려면 m이 작아진다는 것이고 이는 최대한 관계를 보존하면서 차원을 줄이는 축을 찾는 것이다.) LLE는 훈련 인스턴스를 매우 큰 차원에서 낮은 차원으로 매핑하는 데 사용되며, 뒤틀린 매니폴드를 효과적으로 펼치는 데 유용하다.


Other Dimensionality Reduction Techniques

    다른 많은 차원 축소 기술이 있으며 그 중 일부는 Scikit-Learn에서 사용할 수 있다. 가장 인기 있는 것들은 다음과 같다.

  • Random Projections (무작위 투영)
  • Multidimensional Scaling(다차원척도법, MDS)
  • Isomap
  • t-Distributed Stochastic Neighbor Embedding(t-분산 확률적 이웃 임베딩, t-SNE)
  • Linear Discriminant Analysis(선형 판별 분석, LDA)

주섬주섬

  • 가장 적절한 차원 축소 알고리즘은 데이터 셋과 목표에 따라 다르다.

 

반응형

댓글