같은 대수, 서로 다른 해석
고유값 문제는 데이터 분석과 웹 그래프, 물리학에서 모두 등장해. 계산식이 비슷해도 행렬이 무엇을 나타내고 결과를 어떻게 해석하는지는 분야마다 달라. ‘고유’라는 이름만 보고 같은 현상이라고 생각하지 마.
PCA — 분산이 큰 직교 방향 찾기
각 행이 표본, 각 열이 특성인 데이터 를 먼저 중심화해. 공분산행렬은 특성들이 함께 변하는 정도를 담고, 대칭행렬이라 서로 직교하는 고유벡터를 가질 수 있어. 가장 큰 고유값에 대응하는 고유벡터가 데이터의 분산을 가장 크게 잡는 첫 주성분이야.
상위 개 주성분에 투영하면 선형 부분공간 가운데 투영 분산을 최대화하고, 같은 조건에서 제곱 재구성 오차를 최소화해. 이것이 모든 의미의 ‘정보 손실 최소’라는 뜻은 아니고, 비선형 구조나 과제에 중요한 작은 분산 신호는 놓칠 수 있어. 2차원 PCA 그림도 원래 구조의 근사라는 표시가 필요해.
PageRank — 감쇠가 있는 무작위 이동
웹페이지를 노드, 링크를 이동 가능성으로 보면 열확률 전이행렬 을 만들 수 있어. PageRank는 링크를 따라가다가 일정 확률로 임의 페이지로 이동하는 감쇠를 더해, 끊긴 페이지와 순환 같은 문제를 다뤄. 그 수정된 전이과정의 정상분포가 페이지 점수가 돼.
행렬을 직접 고유분해하지 않고도 벡터에 전이행렬을 반복 적용하는 거듭제곱법으로 정상분포를 근사할 수 있어. 수렴은 감쇠와 행렬 조건 덕분에 보장되는 것이지, 모든 그래프에서 무조건 빠른 마법은 아니야.
양자역학 — 연산자의 가능한 측정값
양자 상태는 복소 힐베르트 공간의 벡터나 밀도연산자로 표현하고, 관측가능량은 에르미트 연산자로 나타내. 그 연산자의 고유값은 가능한 측정 결과와, 고유공간은 해당 결과에 연결돼. 일반 상태를 고유상태의 중첩으로 펼칠 수 있고 측정 확률은 상태의 투영 크기에서 나와.
‘관측하면 한 고유벡터로 붕괴한다’는 설명은 입문용 측정 공준의 한 표현이야. 퇴맞음과 혼합상태, 해석 문제까지 한 문장으로 끝난다고 생각하진 마.
SVD — 직사각 행렬의 좌우 방향
고유값 문제는 정방행렬에 정의돼. 특이값분해는 직사각 행렬까지 포함해 로 분해하고, 입력 공간의 오른쪽 특이벡터를 출력 공간의 왼쪽 특이벡터로 보내는 축과 배율을 보여 줘. 특이값의 제곱은 의 고유값과 연결돼.
SVD는 저랭크 근사와 이미지 압축, 잠재 의미 분석, 추천 시스템의 기초 도구로 쓰여. ‘직사각 행렬의 eigen’이라는 별명은 직관에 도움을 주지만 고유값과 특이값을 같은 것으로 만들지는 않아.
트랙 보상
행렬을 변환으로 보고, 역행렬과 행렬식의 한계를 지나, 고유방향과 특이방향까지 왔어. 이제 스펙트럴 방법을 만나면 이름에 겁먹기보다 어떤 행렬을 왜 분해하는지 먼저 물을 수 있어.
아직 완전히 와닿진 않지만 eigen을 이렇게 쓰는거구나. pagerank알고리즘은 천재적이다
import numpy as np import matplotlib.pyplot as plt
rng = np.random.default_rng(42)
잠재 구조가 있는 100x5 데이터: 두 숨은 요인이 5개 열을 만든다
n = 100 f1 = rng.standard_normal(n) f2 = rng.standard_normal(n) X = np.column_stack([ f1 + 0.3rng.standard_normal(n), f1 + 0.3rng.standard_normal(n), f2 + 0.3rng.standard_normal(n), f2 + 0.3rng.standard_normal(n), 0.5f1 + 0.5f2 + 0.3*rng.standard_normal(n), ])
1) 열별 표준화 (평균 0, 표준편차 1)
Xs = (X - X.mean(axis=0)) / X.std(axis=0)
2) 공분산 행렬
C = (Xs.T @ Xs) / (n - 1)
3) 대칭행렬 고유분해
vals, vecs = np.linalg.eigh(C)
4) 큰 고유값 순으로 정렬
order = np.argsort(vals)[::-1] vals = vals[order] vecs = vecs[:, order]
5) 처음 두 주성분으로 사영
PC = Xs @ vecs[:, :2]
print("고유값:", np.round(vals, 4)) print("분산 설명 비율:", np.round(vals / vals.sum(), 4)) print("누적:", np.round(np.cumsum(vals / vals.sum()), 4))
6) PC1 vs PC2 산점도
fig, ax = plt.subplots(figsize=(7, 6)) ax.scatter(PC[:, 0], PC[:, 1], s=40, alpha=0.7, edgecolor='white', linewidth=0.5) ax.axhline(0, color='gray', lw=0.5) ax.axvline(0, color='gray', lw=0.5) ax.set_xlabel(f"PC1 ({vals[0]/vals.sum()*100:.1f}%)") ax.set_ylabel(f"PC2 ({vals[1]/vals.sum()*100:.1f}%)") ax.set_title("PCA: first two principal components") ax.set_aspect('equal', adjustable='datalim') plt.tight_layout() plt.savefig('pca_scatter.png', dpi=130)