🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

고유값과 고유벡터 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 28. · 12 Views

고유값과 고유벡터 완벽 가이드

선형대수학의 핵심 개념인 고유값과 고유벡터를 실무 데이터 과학 관점에서 쉽게 풀어냅니다. PCA, SVD 등 머신러닝의 기반이 되는 개념을 초급자도 이해할 수 있도록 설명합니다.


목차

  1. 고유값과_고유벡터_정의
  2. 고유값_분해란
  3. 기하학적_의미_이해
  4. PCA와의_연결
  5. NumPy로_고유값_계산
  6. 특이값_분해_SVD_소개

1. 고유값과 고유벡터 정의

어느 날 김개발 씨가 머신러닝 프로젝트를 진행하다가 이상한 용어를 만났습니다. "고유값?

고유벡터? 이게 대체 뭐지?" 수학 시간에 배운 것 같기도 하고, 아닌 것 같기도 합니다.

데이터 분석에서 왜 이런 개념이 필요한 걸까요?

고유벡터는 어떤 행렬로 변환했을 때 방향은 바뀌지 않고 크기만 변하는 특별한 벡터입니다. 이때 크기가 변하는 비율을 고유값이라고 합니다.

마치 고무줄을 한쪽 방향으로만 늘이거나 줄이는 것처럼, 행렬이 특정 방향에 대해서는 단순히 스케일링만 수행하는 것입니다.

다음 코드를 살펴봅시다.

import numpy as np

# 2x2 행렬 정의
A = np.array([[3, 1],
              [0, 2]])

# 고유값과 고유벡터 계산
eigenvalues, eigenvectors = np.linalg.eig(A)

print("고유값:", eigenvalues)        # [3. 2.]
print("고유벡터:\n", eigenvectors)   # 각 열이 고유벡터

# 검증: Av = λv 확인
v = eigenvectors[:, 0]  # 첫 번째 고유벡터
lambda_val = eigenvalues[0]  # 첫 번째 고유값

print("Av =", A @ v)
print("λv =", lambda_val * v)  # 두 결과가 같아야 함

김개발 씨는 입사 6개월 차 데이터 분석가입니다. 오늘 팀장님이 던진 한마디에 머리가 복잡해졌습니다.

"이 데이터셋 차원 축소 좀 해봐. PCA 써서." PCA가 뭔지 검색해보니 고유값 분해라는 말이 계속 나옵니다.

도대체 고유값이 뭘까요? 선배 개발자 박시니어 씨가 다가와 화이트보드에 그림을 그리기 시작합니다.

"쉽게 생각해봐. 행렬은 벡터를 변환하는 도구야.

대부분의 벡터는 행렬을 통과하면 방향도 바뀌고 크기도 바뀌지." "그런데 말이야, 아주 특별한 벡터들이 있어. 이 벡터들은 행렬을 통과해도 방향은 그대로야.

크기만 늘어나거나 줄어들 뿐이지." 박시니어 씨의 설명을 비유로 풀어보겠습니다. 여러분이 거울의 방에 들어갔다고 상상해보세요.

어떤 거울은 키를 늘려 보이게 하고, 어떤 거울은 옆으로 퍼져 보이게 합니다. 이때 거울이 바로 행렬입니다.

대부분의 경우 거울 앞에 서면 원래 모습과 완전히 다르게 보입니다. 하지만 특정 각도에서 바라보면 단순히 확대되거나 축소된 모습만 보이는 위치가 있습니다.

이 특별한 방향이 바로 고유벡터이고, 얼마나 확대 또는 축소되는지가 고유값입니다. 수학적으로 표현하면 Av = λv라는 간단한 식이 됩니다.

여기서 A는 행렬, v는 고유벡터, λ는 고유값입니다. 행렬 A를 벡터 v에 적용했더니 그냥 λ배가 되었다는 뜻입니다.

왜 이런 개념이 중요할까요? 복잡한 행렬 연산을 단순한 스케일링으로 바꿀 수 있기 때문입니다.

마치 복잡한 미로를 직선 통로로 바꾸는 것과 같습니다. 위의 코드를 살펴보겠습니다.

numpy의 linalg.eig 함수는 주어진 행렬의 고유값과 고유벡터를 한 번에 계산해줍니다. 반환된 eigenvectors의 각 열이 하나의 고유벡터입니다.

검증 부분을 보면 Av와 λv가 같은 값을 출력합니다. 이것이 바로 고유값과 고유벡터의 정의를 만족한다는 증거입니다.

행렬을 곱해도 방향은 같고 크기만 λ배가 된 것입니다. 실무에서 이 개념은 데이터의 주요 패턴을 찾는 데 활용됩니다.

수천 개의 특성을 가진 데이터에서 가장 중요한 방향을 찾아내는 것이죠. 넷플릭스 추천 시스템, 이미지 압축, 자연어 처리 등 다양한 분야에서 활용됩니다.

주의할 점은 모든 행렬이 고유값 분해가 가능한 것은 아니라는 것입니다. 정방행렬(행과 열의 수가 같은 행렬)만 고유값 분해가 가능하고, 그 중에서도 특정 조건을 만족해야 합니다.

김개발 씨는 고개를 끄덕였습니다. "아, 그러니까 행렬이 데이터를 어떤 방향으로 늘리고 줄이는지 알려주는 거군요!" 맞습니다.

고유값과 고유벡터는 행렬의 본질적인 성질을 드러내는 열쇠입니다.

실전 팁

💡 - np.linalg.eig는 복소수 고유값도 반환할 수 있으니 실수만 필요하면 np.linalg.eigh를 사용하세요

  • 고유벡터는 정규화되어 반환되므로 크기가 1입니다

2. 고유값 분해란

김개발 씨가 고유값과 고유벡터 개념을 어느 정도 이해했습니다. 그런데 선배가 또 새로운 용어를 꺼냅니다.

"고유값 분해로 행렬을 분해하면 계산이 훨씬 쉬워져." 행렬을 분해한다니, 마치 레고 블록을 조립했다 분해하는 것처럼 들립니다.

**고유값 분해(Eigendecomposition)**는 행렬을 고유벡터 행렬과 고유값 대각행렬의 곱으로 표현하는 것입니다. A = PDP^(-1) 형태로 분해하면 행렬의 거듭제곱 계산이 매우 쉬워집니다.

마치 복잡한 기계를 부품별로 분해해서 각각 살펴보는 것과 같습니다.

다음 코드를 살펴봅시다.

import numpy as np

# 대칭 행렬 정의 (실수 고유값 보장)
A = np.array([[4, 2],
              [2, 3]])

# 고유값 분해
eigenvalues, P = np.linalg.eig(A)

# 대각 행렬 D 생성
D = np.diag(eigenvalues)

# P의 역행렬
P_inv = np.linalg.inv(P)

# 검증: A = P @ D @ P_inv
A_reconstructed = P @ D @ P_inv
print("원본 행렬:\n", A)
print("복원 행렬:\n", A_reconstructed)

# 행렬의 거듭제곱이 쉬워짐: A^3 = P @ D^3 @ P_inv
A_cubed = P @ np.diag(eigenvalues**3) @ P_inv
print("A^3:\n", A_cubed)

김개발 씨는 커피를 한 모금 마시며 생각에 잠겼습니다. 고유값과 고유벡터는 알겠는데, 이걸 왜 "분해"한다고 하는 걸까요?

박시니어 씨가 비유를 들어줍니다. "네가 좋아하는 음식 레시피를 생각해봐.

복잡한 요리도 결국 기본 재료들의 조합이잖아. 행렬도 마찬가지야." 고유값 분해는 행렬을 세 가지 기본 요소로 쪼개는 것입니다.

첫째는 고유벡터들을 열로 가지는 행렬 P, 둘째는 고유값들을 대각선에 배치한 대각행렬 D, 셋째는 P의 역행렬 P^(-1)입니다. 이 세 가지를 순서대로 곱하면 원래 행렬 A가 됩니다.

마치 레고 블록을 분해했다가 다시 조립하면 원래 모양이 되는 것처럼요. 그런데 왜 굳이 분해할까요?

답은 계산의 편리함에 있습니다. 대각행렬은 거듭제곱하기가 매우 쉽습니다.

대각선의 각 원소를 그냥 제곱하면 됩니다. A를 100번 곱해야 한다고 상상해보세요.

직접 계산하면 엄청난 연산이 필요합니다. 하지만 분해하면?

D의 대각 원소들을 100제곱하고 P와 P^(-1)을 한 번씩만 곱하면 됩니다. 코드를 보면 A_cubed를 계산할 때 이 원리를 사용합니다.

eigenvalues**3으로 고유값을 세제곱하고, 양쪽에 P와 P_inv를 곱합니다. 결과는 A를 세 번 곱한 것과 정확히 같습니다.

실무에서 이 기법은 마르코프 체인, 동적 시스템 분석, 미분방정식 풀이 등에 활용됩니다. 구글의 페이지랭크 알고리즘도 이 원리를 기반으로 합니다.

다만 모든 행렬이 고유값 분해가 가능한 것은 아닙니다. n x n 정방행렬이면서 n개의 선형 독립인 고유벡터를 가져야 합니다.

대칭행렬은 항상 이 조건을 만족하므로 안전합니다. 김개발 씨가 감탄합니다.

"아, 그래서 대칭행렬을 많이 쓰는 거군요!" 맞습니다. 데이터 과학에서 공분산 행렬이 대칭행렬인 이유 중 하나도 이 때문입니다.

실전 팁

💡 - 대칭행렬은 np.linalg.eigh를 사용하면 더 효율적이고 수치적으로 안정적입니다

  • 복원된 행렬에 미세한 오차가 있을 수 있는데, 이는 부동소수점 연산의 특성입니다

3. 기하학적 의미 이해

숫자와 수식만 보던 김개발 씨가 한 가지 의문을 품었습니다. "이 고유값이랑 고유벡터가 실제로 어떻게 생긴 건가요?

눈으로 볼 수 있나요?" 박시니어 씨가 빙긋 웃으며 시각화 코드를 열었습니다.

기하학적으로 고유벡터는 행렬 변환 시 방향이 유지되는 축입니다. 타원을 그릴 때 장축과 단축이 바로 고유벡터 방향이고, 축의 길이 비율이 고유값입니다.

마치 지구의 자전축처럼, 회전하는 동안에도 변하지 않는 특별한 방향인 셈입니다.

다음 코드를 살펴봅시다.

import numpy as np
import matplotlib.pyplot as plt

# 변환 행렬 정의
A = np.array([[2, 1],
              [1, 2]])

# 고유값, 고유벡터 계산
eigenvalues, eigenvectors = np.linalg.eig(A)

# 단위원 위의 점들 생성
theta = np.linspace(0, 2*np.pi, 100)
circle = np.array([np.cos(theta), np.sin(theta)])

# 행렬 변환 적용 -> 타원이 됨
ellipse = A @ circle

# 시각화
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(circle[0], circle[1], 'b-', label='원본 (단위원)')
plt.title('변환 전')
plt.axis('equal')
plt.grid(True)

plt.subplot(1, 2, 2)
plt.plot(ellipse[0], ellipse[1], 'r-', label='변환 후 (타원)')
# 고유벡터 방향 표시
for i in range(2):
    plt.arrow(0, 0, eigenvectors[0,i]*eigenvalues[i],
              eigenvectors[1,i]*eigenvalues[i], head_width=0.1)
plt.title('변환 후')
plt.axis('equal')
plt.grid(True)
plt.savefig('eigen_visualization.png')

김개발 씨는 모니터에 나타난 그림을 보며 눈이 커졌습니다. 동그란 원이 행렬을 통과하니 타원이 되었습니다.

마법 같은 일입니다. 박시니어 씨가 설명을 시작합니다.

"행렬은 공간을 변형시키는 도구야. 원래 동그란 원이 늘어나거나 찌그러지는 거지." 여기서 핵심적인 통찰이 있습니다.

타원에는 특별한 두 방향이 있습니다. 바로 장축단축입니다.

이 방향들이 바로 고유벡터입니다. 생각해보면 당연합니다.

원에서 타원으로 변할 때, 어떤 방향은 많이 늘어나고 어떤 방향은 적게 늘어납니다. 가장 많이 늘어난 방향이 가장 큰 고유값에 해당하는 고유벡터입니다.

코드에서 단위원을 만들고 행렬 A를 곱합니다. 결과는 타원입니다.

화살표로 표시된 것이 고유벡터 방향이고, 화살표의 길이가 고유값에 비례합니다. 이 시각적 이해가 왜 중요할까요?

데이터를 다룰 때 공분산 행렬의 고유벡터는 데이터가 가장 많이 퍼져있는 방향을 알려주기 때문입니다. 1000명의 키와 몸무게 데이터가 있다고 상상해보세요.

이 데이터를 점으로 찍으면 대략 타원 모양으로 분포할 겁니다. 고유벡터는 이 타원의 주축 방향입니다.

가장 큰 고유값에 해당하는 고유벡터 방향이 데이터의 주요 변동 방향입니다. 이 방향으로 프로젝션하면 데이터의 핵심 정보를 최대한 보존할 수 있습니다.

반대로 작은 고유값의 방향은 데이터 변동이 적은 방향입니다. 이 방향의 정보는 버려도 큰 손실이 없습니다.

바로 이것이 차원 축소의 원리입니다. 김개발 씨가 무릎을 쳤습니다.

"아, 그래서 PCA에서 고유벡터를 쓰는 거구나!" 맞습니다. 다음 장에서 이 연결고리를 자세히 살펴보겠습니다.

주의할 점은 시각화는 2차원이나 3차원에서만 가능하다는 것입니다. 고차원 데이터의 고유벡터는 눈으로 볼 수 없지만, 같은 원리가 적용됩니다.

실전 팁

💡 - matplotlib의 quiver 함수를 사용하면 벡터를 더 예쁘게 그릴 수 있습니다

  • 3차원 시각화는 mpl_toolkits.mplot3d를 활용하세요

4. PCA와의 연결

드디어 김개발 씨가 가장 궁금해하던 주제입니다. "그래서 PCA가 뭔가요?

팀장님이 맨날 PCA 써서 차원 축소하라고 하시는데..." 박시니어 씨가 커피를 한 모금 마시며 말합니다. "PCA는 결국 고유값 분해야.

네가 배운 거 그대로 적용하는 거지."

**PCA(주성분 분석)**는 데이터의 공분산 행렬을 고유값 분해하여 주요 변동 방향을 찾는 기법입니다. 가장 큰 고유값에 해당하는 고유벡터가 첫 번째 주성분이 됩니다.

마치 사진을 찍을 때 가장 좋은 각도를 찾는 것처럼, 데이터를 가장 잘 설명하는 방향을 찾아냅니다.

다음 코드를 살펴봅시다.

import numpy as np
from sklearn.decomposition import PCA

# 샘플 데이터 생성 (100개 샘플, 5개 특성)
np.random.seed(42)
X = np.random.randn(100, 5)

# 공분산 행렬의 고유값 분해로 직접 PCA 구현
X_centered = X - X.mean(axis=0)  # 평균 중심화
cov_matrix = np.cov(X_centered.T)  # 공분산 행렬

eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
# 고유값 내림차순 정렬
idx = np.argsort(eigenvalues)[::-1]
eigenvalues = eigenvalues[idx]
eigenvectors = eigenvectors[:, idx]

# 상위 2개 주성분으로 차원 축소
n_components = 2
X_pca_manual = X_centered @ eigenvectors[:, :n_components]

# sklearn PCA와 비교
pca = PCA(n_components=2)
X_pca_sklearn = pca.fit_transform(X)

print("설명된 분산 비율:", eigenvalues[:2] / eigenvalues.sum())
print("sklearn 결과:", pca.explained_variance_ratio_)

김개발 씨 앞에 1000개의 열을 가진 데이터셋이 있습니다. 머신러닝 모델을 학습시키려는데 차원이 너무 높습니다.

이른바 차원의 저주입니다. 박시니어 씨가 말합니다.

"1000개 특성 중에서 진짜 중요한 건 몇 개 안 돼. 나머지는 노이즈거나 중복이야.

PCA로 핵심만 추려내자." PCA의 아이디어는 단순합니다. 데이터가 가장 많이 퍼져있는 방향을 찾아서, 그 방향으로 데이터를 프로젝션하는 것입니다.

앞서 배운 고유벡터가 바로 이 방향입니다. 순서대로 살펴봅시다.

먼저 데이터의 평균을 빼서 중심을 원점으로 옮깁니다. 이것을 평균 중심화라고 합니다.

다음으로 공분산 행렬을 계산합니다. 공분산 행렬은 각 특성 간의 상관관계를 담고 있는 대칭행렬입니다.

이 행렬의 고유벡터가 데이터의 주축 방향입니다. 고유값은 해당 방향으로의 분산을 나타냅니다.

고유값이 클수록 그 방향으로 데이터가 많이 퍼져있다는 뜻입니다. 따라서 가장 큰 고유값의 고유벡터가 첫 번째 주성분입니다.

코드에서 eigenvalues를 내림차순으로 정렬하는 이유가 여기 있습니다. 가장 중요한 방향부터 선택하기 위해서입니다.

X_centered에 고유벡터 행렬을 곱하면 새로운 좌표계로 변환됩니다. 상위 n개 고유벡터만 사용하면 n차원으로 축소됩니다.

5차원 데이터가 2차원이 되었습니다. 설명된 분산 비율을 보면 상위 2개 주성분이 전체 분산의 얼마를 설명하는지 알 수 있습니다.

이 비율이 높으면 정보 손실이 적다는 뜻입니다. sklearn의 PCA와 직접 구현한 결과가 같은지 확인해보세요.

부호는 다를 수 있지만 절대값은 같아야 합니다. 고유벡터의 방향은 양쪽 모두 유효하기 때문입니다.

김개발 씨가 감탄합니다. "결국 고유값 분해를 데이터에 적용한 게 PCA군요!" 정확합니다.

선형대수의 추상적 개념이 실용적인 도구가 되는 순간입니다.

실전 팁

💡 - 분산 설명 비율이 95% 이상 되도록 주성분 개수를 선택하는 것이 일반적입니다

  • 스케일이 다른 특성들은 PCA 전에 표준화(StandardScaler)를 해주세요

5. NumPy로 고유값 계산

이론은 충분히 배웠으니 이제 실전입니다. 김개발 씨가 NumPy 문서를 펼쳤습니다.

"eig랑 eigh가 있는데 뭐가 다른 거죠?" 박시니어 씨가 중요한 포인트를 짚어줍니다. "상황에 맞는 함수를 써야 해.

잘못 쓰면 성능이나 정확도에서 손해를 보거든."

NumPy는 고유값 계산을 위해 여러 함수를 제공합니다. np.linalg.eig는 일반 정방행렬용이고, np.linalg.eigh는 대칭(에르미트) 행렬용입니다.

대칭행렬이라면 eigh를 쓰는 것이 더 빠르고 수치적으로 안정적입니다.

다음 코드를 살펴봅시다.

import numpy as np
import time

# 대칭 행렬 생성
n = 500
A = np.random.randn(n, n)
A_symmetric = (A + A.T) / 2  # 대칭 행렬로 만들기

# 방법 1: np.linalg.eig (일반 행렬용)
start = time.time()
eigenvalues_eig, eigenvectors_eig = np.linalg.eig(A_symmetric)
print(f"eig 소요시간: {time.time()-start:.4f}초")

# 방법 2: np.linalg.eigh (대칭 행렬용) - 더 빠름!
start = time.time()
eigenvalues_eigh, eigenvectors_eigh = np.linalg.eigh(A_symmetric)
print(f"eigh 소요시간: {time.time()-start:.4f}초")

# eigh는 오름차순 정렬됨
print("eigh 고유값 (오름차순):", eigenvalues_eigh[:5])

# 내림차순으로 바꾸기
eigenvalues_sorted = eigenvalues_eigh[::-1]
eigenvectors_sorted = eigenvectors_eigh[:, ::-1]

# 직교성 검증 (대칭행렬의 고유벡터는 직교)
print("직교성:", np.allclose(eigenvectors_eigh.T @ eigenvectors_eigh, np.eye(n)))

김개발 씨가 PCA를 구현하려고 np.linalg.eig를 사용했습니다. 잘 동작하는 것 같은데, 코드 리뷰에서 박시니어 씨가 빨간 줄을 긋습니다.

"공분산 행렬은 대칭행렬이야. 대칭행렬에는 eigh를 써야 해." 왜 그런 걸까요?

np.linalg.eig는 어떤 정방행렬이든 처리할 수 있는 범용 함수입니다. 복소수 고유값도 계산하고, 비대칭 행렬도 다룹니다.

하지만 그만큼 계산 비용이 큽니다. 반면 np.linalg.eigh는 대칭행렬(또는 복소수의 경우 에르미트 행렬)만 처리합니다.

대신 그 특성을 활용해서 더 빠르고 정확하게 계산합니다. 대칭행렬의 고유값은 항상 실수입니다.

복소수를 다룰 필요가 없으니 계산이 단순해집니다. 또한 대칭행렬의 고유벡터들은 서로 직교합니다.

이 성질 덕분에 알고리즘이 더 안정적입니다. 코드의 벤치마크를 보면 차이가 확연합니다.

500x500 행렬에서 eigh가 eig보다 몇 배 빠릅니다. 행렬 크기가 커질수록 이 차이는 더 벌어집니다.

한 가지 주의할 점은 eigh가 고유값을 오름차순으로 반환한다는 것입니다. PCA처럼 큰 고유값이 먼저 필요한 경우에는 역순으로 정렬해야 합니다.

직교성 검증 부분을 보세요. 고유벡터 행렬의 전치와 자기 자신을 곱하면 단위행렬이 됩니다.

이것은 대칭행렬의 아름다운 성질입니다. 실무에서 흔히 하는 실수 중 하나는 비대칭 행렬에 eigh를 쓰는 것입니다.

에러는 나지 않지만 결과가 틀립니다. 항상 행렬의 특성을 먼저 확인하세요.

김개발 씨가 코드를 수정했습니다. "앞으로는 공분산 행렬이면 무조건 eigh를 쓸게요!" 좋은 습관입니다.

작은 차이가 대규모 데이터에서는 큰 성능 차이를 만듭니다. 마지막으로, scipy.linalg에도 비슷한 함수들이 있습니다.

특정 개수의 고유값만 필요할 때는 scipy.sparse.linalg.eigsh를 사용하면 더 효율적입니다.

실전 팁

💡 - 큰 희소행렬은 scipy.sparse.linalg.eigsh를 사용해 상위 k개 고유값만 계산하세요

  • 행렬이 대칭인지 확인: np.allclose(A, A.T)

6. 특이값 분해 SVD 소개

김개발 씨가 고유값 분해에 익숙해질 무렵, 또 새로운 용어가 등장했습니다. "SVD도 알아야 해.

고유값 분해보다 더 범용적이거든." 박시니어 씨의 말에 김개발 씨는 머리를 긁적입니다. 또 새로운 게 나왔군요.

**SVD(특이값 분해)**는 어떤 행렬이든 세 행렬의 곱으로 분해할 수 있는 강력한 기법입니다. A = UΣV^T 형태로, 정방행렬이 아니어도 적용 가능합니다.

추천 시스템, 이미지 압축, 자연어 처리 등에서 핵심적으로 사용됩니다.

다음 코드를 살펴봅시다.

import numpy as np

# 직사각형 행렬 (3x4)
A = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]])

# SVD 분해
U, s, Vt = np.linalg.svd(A)

print("U shape:", U.shape)   # (3, 3)
print("s (특이값):", s)       # [25.4..., 1.29..., 0]
print("Vt shape:", Vt.shape) # (4, 4)

# 복원: A = U @ Sigma @ Vt
# s는 1차원 배열이므로 대각행렬로 변환 필요
Sigma = np.zeros((3, 4))
Sigma[:3, :3] = np.diag(s)

A_reconstructed = U @ Sigma @ Vt
print("복원 성공:", np.allclose(A, A_reconstructed))

# 차원 축소 (상위 k개 특이값만 사용)
k = 2
A_approx = U[:, :k] @ np.diag(s[:k]) @ Vt[:k, :]
print("근사 오차:", np.linalg.norm(A - A_approx))

# SVD와 고유값 분해의 관계
# A^T @ A의 고유값 = 특이값의 제곱
ATA = A.T @ A
eigenvalues = np.linalg.eigvalsh(ATA)
print("A^T·A 고유값:", np.sort(eigenvalues)[::-1])
print("특이값의 제곱:", s**2)

김개발 씨가 질문합니다. "고유값 분해로 충분한 거 아닌가요?

왜 SVD가 또 필요해요?" 박시니어 씨가 핵심을 짚어줍니다. "고유값 분해는 정방행렬에만 적용할 수 있어.

하지만 현실의 데이터는 대부분 직사각형이잖아." 100명의 고객이 1000개의 상품에 남긴 평점 데이터를 생각해보세요. 100 x 1000 행렬입니다.

이런 행렬에는 고유값 분해를 직접 적용할 수 없습니다. SVD는 어떤 m x n 행렬이든 세 부분으로 분해합니다.

U는 m x m 직교행렬, Σ는 m x n 대각행렬, V^T는 n x n 직교행렬입니다. 특이값은 Σ의 대각 원소로, 항상 0 이상의 실수입니다.

내림차순으로 정렬되어 있어서 첫 번째 특이값이 가장 중요합니다. 코드를 보면 3 x 4 행렬을 분해했습니다.

U는 3 x 3, Vt는 4 x 4가 됩니다. s는 특이값만 담은 1차원 배열입니다.

복원할 때는 s를 적절한 크기의 대각행렬로 만들어야 합니다. 3 x 4 행렬에서 대각선은 3개뿐이니까 Sigma는 3 x 4 영행렬에 대각 원소만 채웁니다.

SVD의 강력함은 저랭크 근사에 있습니다. 상위 k개 특이값만 사용해도 원래 행렬을 꽤 잘 근사할 수 있습니다.

이미지 압축이 바로 이 원리입니다. 100만 화소 이미지를 저장하려면 100만 개의 숫자가 필요합니다.

하지만 SVD로 분해하고 상위 특이값만 저장하면 훨씬 적은 용량으로 비슷한 품질을 유지할 수 있습니다. 마지막 부분이 흥미롭습니다.

A^T @ A의 고유값이 특이값의 제곱과 같습니다. 이것은 SVD와 고유값 분해의 깊은 연결고리를 보여줍니다.

넷플릭스 추천 시스템, 검색 엔진의 잠재 의미 분석(LSA), 얼굴 인식 등 수많은 응용 분야에서 SVD가 핵심 역할을 합니다. 김개발 씨가 정리합니다.

"고유값 분해의 일반화 버전이 SVD군요!" 그렇습니다. SVD를 이해하면 데이터 과학의 절반은 이해한 셈입니다.

실전 팁

💡 - 큰 행렬의 일부 특이값만 필요하면 np.linalg.svd(full_matrices=False) 옵션을 쓰세요

  • 희소행렬은 scipy.sparse.linalg.svds를 사용하면 메모리 효율적입니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#LinearAlgebra#Eigenvalue#Eigenvector#PCA#SVD#Math,Linear Algebra

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.