머신러닝과 PCA - 데이터의 차원과 복잡성

소환인·2024년 1월 5일
0

스터디노트

목록 보기
48/48

들어가며

머신러닝을 공부하면서 처음으로 골머리를 앓았던 부분이 주성분 분석(Principal Component Analysis, PCA)를 이해하는 것이었습니다. 머신러닝과 딥러닝의 많은 개념들이 선형대수학과 미적분학에 기초하고 있는데, 그에 대한 이해가 부족해서 처음 PCA에 대한 설명을 들었을 땐 쉽게 이해하기 어려웠습니다. 강의를 통해, 그리고 인터넷을 통해 찾은 좋은 자료들로 PCA에 대해 공부한 내용들을 이 포스트를 통해 정리해보겠습니다.

머신러닝은 데이터에서 의미 있는 패턴을 발견하고 이를 통해 예측 또는 분류를 수행합니다. 데이터의 차원, 즉 특성의 수는 모델의 성능과 해석 가능성에 영향을 미칩니다. 높은 차원의 데이터는 종종 "차원의 저주"로 불리는 문제를 야기하며, 이는 과적합, 긴 계산 시간, 데이터 해석의 어려움 등을 뜻합니다.

이러한 문제를 해결하기 위해 차원 축소 기법이 널리 사용됩니다. 차원 축소는 복잡한 데이터셋을 더 작은 차원의 데이터셋으로 변환하는 것입니다. 데이터의 핵심적인 정보는 유지하면서 불필요한 정보를 제거합니다. 주성분 분석은 가장 널리 사용되는 차원 축소 기법 중 하나입니다.

PCA는 고차원 데이터에서 가장 중요한 특성을 추출하여 차원의 수를 줄이는 기법입니다. PCA는 데이터의 공분산 행렬을 분석하여 이루어지며, 공분산 행렬의 고유값과 고유벡터를 찾아서 데이터를 고유벡터로 정사영하는 것이 차원 축소의 개념입니다. 이러한 수학적 과정을 통해 데이터의 주요 변동성을 포착하는 주성분을 도출할 수 있습니다.

본 포스트에서는 머신러닝을 공부하는 입장에서 공분산 행렬, 고유값과 고유벡터, PCA에 대해 자세히 설명하고, 스크리 플롯을 활용하여 주성분의 수를 선택하는 방법을 실습 코드와 함께 정리하겠습니다.

이 포스트는 공돌이의 수학정리노트 블로그를 참고하였습니다.

공분산 행렬(Covariance Matrix)

공분산 행렬은 다변량 데이터에서 각 변수 간의 공분산을 요약한 n×nn \times n 크기의 정사각 행렬입니다. 여기서 nn은 변수의 개수입니다. 공분산 행렬은 아래와 같은 특성을 같습니다.

  • 대칭성: 공분산 행렬은 대칭 행렬입니다. 대각 요소를 기준으로 상위 삼각부와 하위 삼각부가 서로 대칭입니다. 즉, Cov(Xi,Xj)=Cov(Xj,Xi)\text{Cov}(X_i, X_j) = \text{Cov}(X_j, X_i) 입니다.

  • 분산의 계산: 공분산 행렬에서 대각선 요소는 해당 변수의 분산을 나타내며, 이는 데이터가 해당 변수에 대해 얼마나 퍼져 있는지(즉, 얼마나 변동하는지)를 나타냅니다.

  • 공분산의 계산: 비대각선 요소는 두 변수 간의 공분산을 나타내며, 이는 두 변수가 함께 얼마나 변동하는지를 나타냅니다. 양의 값은 변수가 같은 방향으로 변동한다는 것을, 음의 값은 변수가 반대 방향으로 변동한다는 것을 의미합니다.

파이썬에선 넘파이를 이용해 공분산 행렬을 만들 수 있습니다.

import numpy as np

# 예시 데이터
X = np.array([[1, 2], [3, 4], [5, 6]])

# 평균을 빼서 데이터를 표준화
X_standardized = X - np.mean(X, axis=0)

# 공분산 행렬 계산
cov_matrix = np.cov(X_standardized, rowvar=False)
array([[4., 4.],
       [4., 4.]])

XX는 3개의 행과 2개의 열을 갖고 있습니다. 공분산 행렬은 특성의 개수를 크기로 하는 정방행렬이라고 했으니 2×22 \times 2 크기가 됩니다. np.cov 함수는 데이터의 공분산 행렬을 반환하며, rowvar=False 매개변수는 입력 데이터의 행이 각각의 관측치를 나타내는지, 아니면 열이 각각의 관측치를 나타내는지를 지정하는 옵션입니다. 이렇게 계산된 공분산 행렬은 PCA를 위해 고유값과 고유벡터를 찾기 위해 사용됩니다.

고유값(Eigenvalues)과 고유벡터(Eigenvectors)

데이터의 분산을 최대로 설명하는 새로운 축을 찾는 것이 PCA의 핵심입니다. 이 새로운 축을 찾기 위해 데이터의 공분산 행렬을 사용하여 고유값과 고유벡터를 계산합니다.

고유값과 고유벡터는 다음과 같이 정의할 수 있습니다.

Cv=λvCv = \lambda v

여기서 vv는 고유벡터, λ\lambda는 해당 고유벡터에 대응하는 고유값입니다. 이 방정식은 공분산 행렬 CC에 벡터 vv를 곱했을 때, 벡터 vv의 스칼라 배인 λv\lambda v가 되는 경우를 설명합니다.

행렬을 열벡터에 대한 선형변환으로 이해한다면, 하나의 벡터 공간을 다른 기저 벡터를 갖는 벡터 공간으로 맵핑(mapping)한다고 볼 수 있습니다. 고유벡터에 대한 수식을 보면, 고유벡터에 공분산 행렬을 곱해 선형변환을 한 결과, 벡터의 방향이 변하지 않고 길이만 달라졌습니다. 고유벡터는 데이터의 변수간의 공분산을 나타낸 공분산 행렬에 의해 변환될 때 방향이 보존되는 벡터로 이해할 수 있습니다.

이 고유벡터를 이용해 데이터의 구조를 유지한 채 차원을 줄일 수 있습니다. 고유벡터 vv는 공분산 행렬이 작용하는 주축의 방향을 보여줍니다. 고유벡터는 데이터의 변동이 가장 큰 방향을 나타내고, 고유값 λ\lambda는 그 변동의 크기를 나타냅니다.

다시 말하면, 데이터를 고유 벡터로 정사영하여 차원을 줄였을 때 그 분산이 고유값이 됩니다. 고유값이 크면 클수록 고유벡터를 축으로 했을 때 데이터의 분산이 더 크다는 뜻입니다. 고유벡터로 데이터를 정사영하여 데이터의 분산(구조)을 유지하며 차원을 축소할 수 있습니다.

cov_matrix = np.array([[2, 1], [1, 2]])

eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)

공분산 행렬과 마찬가지로 넘파이를 이용해 고유값(eigen value)와 고유벡터(eigen vector)를 구할 수 있습니다. np.linalg.eig 함수는 고유값과 고유벡터를 반환합니다.

행렬의 선형변환 및 추가적인 설명이 필요하다면 앞서 소개한 공돌이의 수학정리노트를 추천합니다.

주성분 분석(PCA)

PCA는 고차원 데이터에 포함된 중요한 정보를 보존하면서 차원을 축소하는 기법입니다. PCA는 데이터의 분산을 최대화하는 방향을 찾아내고, 이를 통해 데이터를 새로운 축으로 변환합니다. 이 과정에서 추출된 주성분들은 원본 데이터의 분산을 최대한 설명하는 새로운 특성들입니다.

  • 표준화: PCA를 수행하기 전에 데이터를 표준화하는 것이 일반적입니다. 이는 각 특성이 평균 0, 분산 1을 갖도록 하여 모든 특성이 동일한 스케일을 갖게 합니다.

  • 고유값 분해: 데이터의 공분산 행렬을 고유값 분해하여 고유값과 고유벡터를 찾습니다. 고유벡터는 데이터의 변동이 가장 큰 방향을 나타내고, 고유값은 고유벡터로 데이터를 정사영했을 때의 분산입니다.

  • 차원 축소: 고유값이 큰 순서대로 정렬된 고유벡터를 선택하여, 데이터를 낮은 차원으로 변환합니다. 고유값이 큰 순서대로 고유벡터를 선택하면 결과적으로는 분산이 가장 큰 주성분을 구하는 것이 됩니다. 이 변환은 원본 데이터의 정보 손실을 최소화하면서 차원을 줄입니다.

주성분들은 데이터의 중요한 특성(분산)을 포착하므로, 이를 통해 데이터를 이해하고, 시각화하며, 효율적으로 분석할 수 있습니다. 또한, 머신러닝 모델의 학습 시간을 줄이고, 과적합을 방지하는 데에도 도움을 줄 수 있습니다.

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris

X = load_iris().data

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# PCA 모델 생성 및 주성분 수 설정
pca = PCA(n_components=2)
pca.fit(X_scaled)

# 변환된 데이터
X_pca = pca.transform(X_scaled)

# 주성분의 설명된 분산 비율
print("설명된 분산 비율:", pca.explained_variance_ratio_)
설명된 분산 비율: [0.72962445 0.22850762]

위 코드는 iris 데이터를 스탠다드 스케일러를 사용해 표준화하고 표준화된 데이터에 PCA를 적용하여 주성분을 추출합니다.PCA 클래스의 n_components 매개변수를 사용하여 추출할 주성분의 수를 지정할 수 있습니다. explained_variance_ratio_ 속성은 각 주성분이 원본 데이터의 분산을 얼마나 설명하는지의 비율을 나타냅니다. 이 값이 클수록 해당 주성분은 데이터의 중요한 정보를 많이 포함하고 있다고 볼 수 있습니다.

출력 결과를 보면 첫번째 주성분이 전체 분산의 약 72.96%를 설명하고 있으며, 두 번째 주성분은 추가적으로 22.85%를 설명합니다. 이렇게 두 주성분을 사용하여 원본 데이터의 약 95.81%의 분산을 설명할 수 있음을 알 수 있습니다.

첫 번째 주성분이 많은 분산을 설명하는 것은 그 방향이 데이터의 주요 변동성을 포착하기 때문입니다. 두 번째 주성분은 첫 번째 주성분과 직교하는 방향으로, 남아 있는 분산 중 가장 큰 부분을 설명합니다. 임의의 행렬에 대해 고유벡터가 항상 직교한다고 할 순 없지만, 대칭행렬의 고유벡터들은 서로 직교하는 성질을 갖습니다. 그런데 이 포스트에서 다루고 있는 공분산 행렬은 대칭행렬이기 때문에 공분산 행렬의 고유벡터들은 항상 직교한다고 볼 수 있습니다. 이처럼 PCA는 각 주성분이 서로 직교하도록 데이터를 변환함으로써, 각 주성분이 독립적인 정보를 가지게 만듭니다.

스크리 플롯(Scree Plot)과 주성분 선택

주성분 분석에서 추출할 수 있는 주성분의 최대 개수는 원본 데이터셋의 변수(특성) 수에 의해 결정됩니다. 만약 데이터셋에 dd개의 변수가 있다면, 최대 dd개의 주성분을 추출할 수 있습니다.

주성분의 수를 결정할 때는 데이터의 변동성을 가능한 많이 설명하면서도, 차원의 수를 축소하기 위해 필요한 최소한의 주성분만을 선택하는 것이 중요합니다. 스크리 플롯은 이러한 결정을 돕기 위해 사용되며, 그래프의 '엘보우' 지점은 주성분의 수를 결정하는 데 사용되는 기준점이 됩니다.

스크리 플롯은 PCA 분석에서 각 주성분의 설명된 분산 비율을 시각적으로 나타내는 그래프입니다. X축은 주성분의 수, Y축은 설명된 분산 비율을 나타냅니다. 스크리 플롯에서 주성분의 수에 따른 설명된 분산 비율이 급격히 감소하는 지점을 '엘보우 포인트'라고 합니다.

일반적으로 엘보우 포인트 이전의 주성분들은 데이터에 포함된 중요한 정보를 반영하며, 이 지점 이후의 주성분들은 노이즈나 불필요한 정보를 포함한다고 여겨집니다. 따라서, 엘보우 포인트 이후의 주성분들은 일반적으로 분석에서 제외됩니다.

import matplotlib.pyplot as plt

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

pca = PCA()
pca.fit(X_scaled)

X_pca = pca.transform(X_scaled)
explained_variance = pca.explained_variance_ratio_

# 스크리 플롯 그리기
plt.figure(figsize=(10, 6))
plt.plot(range(1, len(explained_variance) + 1), explained_variance, 'o-', linewidth=2, color='blue')
plt.title('Scree Plot')
plt.xlabel('n_components')
plt.ylabel('explained_variance_ratio')
plt.show()

스크리 플롯에서 첫 번째 주성분부터 시작하여 각 주성분이 데이터의 분산을 얼마나 설명하는지를 시각적으로 살펴볼 수 있습니다. 그래프에서 설명된 분산 비율의 급격한 감소가 멈추는 지점, 즉 '팔꿈치'와 같이 꺾이는 지점을 찾아내면, 그 지점까지의 주성분들로 차원 축소를 수행하는 것이 좋습니다. 여기선 3개의 주성분을 선택하는 것이 좋아보입니다.

하지만 항상 엘보우 포인트의 주성분의 개수를 선택하는 것이 정답은 아니고, 데이터셋의 특성과 분석의 목적을 고려해야 합니다. 스크리 플롯을 통해 상위 몇 개의 주성분이 전체 변동성의 상당 부분을 설명하는지를 파악하고, 모델의 복잡성과 계산 효율성을 고려하여 주성분의 수를 결정합니다.

iris 데이터는 4개의 특성을 갖고 있고, 앞서 살펴봤듯 n_components=2일 때 원본 데이터 분산의 95%를 설명했다는 것을 생각하면 스크리 플롯의 엘보우 포인트로 3개의 주성분을 선택하는 것이 적절해 보이지만, 2개의 주성분만을 선택할 수도 있습니다.


PCA를 통해 데이터의 구조를 보존하며 데이터의 복잡성을 줄여줍니다. 이를 통해 데이터의 노이즈를 줄이고, 데이터를 저장 및 처리 효율성을 향상시킬 수 있습니다. 그 결과, 머신러닝 모델의 학습시간 단축과 성능 향상을 기대할 수 있습니다.

이 포스트에서는 머신러닝을 공부하며 이해하는데 어려움을 겪었던 PCA에 대해 그동안 공부했던 내용들을 정리했습니다. 공분산 행렬의 개념부터 고유값과 고유벡터, 그리고 PCA를 통한 차원 축소의 과정을 설명하려고 했습니다. 또한, 스크리 플롯을 사용하여 데이터 분석에서 중요한 주성분의 수를 결정하는 방법에 대해서도 알아보았습니다.

PCA에 대한 공부를 통해, 머신러닝에서 선형대수학의 개념이 얼마나 중요하고 실용적으로 활용되는지 느끼게 되었습니다. 데이터 과학과 머신러닝을 공부하며 이러한 수학적 개념을 실제 데이터에 적용해보며, 이론과 실습 사이의 간격을 좁힐 수 있었습니다.

profile
돌고돌아

0개의 댓글