Workspace IndexMath › Day 23

PCA and SVD TODO

Math · Day 23 / 52 · September — Linear Algebra (Day 18-26)

Concept

SVD decomposes an arbitrary real matrix A as A = UΣVᵀ, where U and V are orthogonal matrices and Σ is a diagonal matrix holding the nonnegative singular values in decreasing order. Geometrically, this means any linear transformation can be viewed as the composition of 'rotation (or reflection) → axis-wise scaling → rotation'; the size of the singular values indicates how much each direction is stretched, and the number of singular values close to zero indicates how rank-deficient the matrix is. The truncated SVD keeping only the top k singular values has the property (Eckart–Young) of being the optimal rank-k approximation under the Frobenius norm, which is the theoretical basis for dimensionality reduction and noise removal. PCA is the procedure of centering the data by column means and then finding the eigenvectors of the covariance matrix — in the SVD of the centered data matrix, the columns of V are exactly the principal components, and the squared singular values are proportional to the variance explained by each component. In other words, PCA is the statistical interpretation of SVD, and forgetting to center the data is the most common practical pitfall that makes the two results diverge.

Compressing high-dimensional metrics or extracting the dominant axes of variation from correlated signals comes up repeatedly in anomaly detection, risk decomposition, and feature extraction, and reading condition number and rank deficiency is also a basic tool for diagnosing numerical instability.

Code & Formula

# PCA·SVD — 상관된 2D 합성 데이터에서 주성분(최대 분산 방향)을 SVD로 직접 구한다.

import numpy as np

rng = np.random.default_rng(0)
n = 300

# x, y가 강하게 상관되도록 만든 2D 데이터 (주된 퍼짐 방향이 대략 45도가 되게)
t = rng.normal(0, 3, n)
x = t + rng.normal(0, 0.3, n)
y = t * 0.6 + rng.normal(0, 0.3, n)
X = np.column_stack([x, y])  # shape (n, 2)

X_centered = X - X.mean(axis=0)  # PCA는 평균을 원점으로 옮긴 뒤 분산 방향을 찾는다

U, S, Vt = np.linalg.svd(X_centered, full_matrices=False)
print(f"특이값(Σ): {S}")
print("주성분 방향(V의 행, 분산이 큰 순서):\n", Vt)

pc1 = Vt[0]
angle_deg = np.degrees(np.arctan2(pc1[1], pc1[0]))
print(f"\n제1주성분(PC1) 방향 벡터 = {pc1}, x축 대비 각도 ≈ {angle_deg:.1f}도")

# 데이터를 PC1 축 하나에 투영 (2D -> 1D 차원축소)
projected = X_centered @ pc1
explained_var_ratio = (S ** 2) / np.sum(S ** 2)
print(f"\nPC1 하나로 설명되는 분산 비율 = {explained_var_ratio[0]:.4f}")
print(f"투영된 1D 값 예시(앞 5개): {np.round(projected[:5], 3)}")

Exercise

Generate synthetic 2-3 dimensional data with strong correlation, center it and compute the SVD, derive the variance explained by each principal component from the squared-singular-value ratios, and compare how the results differ if you skip centering.

Practical Connection

Arranging multiple markets' price time series as a matrix and extracting principal components can separate a common factor like 'overall market direction' from movements unique to individual markets, which can be used for anomalous price detection and gauging risk concentration.

If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/math-50-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.


한국어

PCA·SVD TODO

Math · Day 23 / 52 · 9월 — 선형대수 (Day 18–26)

개념

SVD는 임의의 실수 행렬 A를 A = UΣVᵀ로 분해하는 것으로, U와 V는 직교행렬이고 Σ는 음이 아닌 특이값을 큰 순서로 담은 대각행렬이다. 기하학적으로는 어떤 선형 변환도 '회전(또는 반사) → 축별 스케일링 → 회전'의 합성으로 볼 수 있다는 뜻이며, 특이값의 크기는 각 방향이 얼마나 늘어나는지를, 0에 가까운 특이값의 개수는 행렬이 얼마나 계수 부족(rank deficient)인지를 말해 준다. 상위 k개의 특이값만 남긴 절단 SVD는 프로베니우스 노름 기준에서 최적의 계수 k 근사라는 성질(Eckart–Young)을 가지며, 이것이 차원 축소와 잡음 제거의 이론적 근거다. PCA는 데이터를 열 평균으로 중심화한 뒤 공분산 행렬의 고유벡터를 찾는 절차인데, 중심화된 데이터 행렬의 SVD에서 V의 열이 바로 그 주성분이고 특이값의 제곱이 각 성분이 설명하는 분산에 비례한다. 즉 PCA는 SVD의 통계적 해석이며, 중심화를 빠뜨리면 두 결과가 달라진다는 점이 실무에서 가장 흔한 함정이다.

고차원 지표를 압축하거나 상관된 신호에서 주요 변동 축을 뽑는 일은 이상 탐지·리스크 분해·특징 추출에서 반복적으로 등장하고, 조건수와 계수 부족을 읽는 것도 수치적 불안정성을 진단하는 기본 도구다.

코드 · 수식

# PCA·SVD — 상관된 2D 합성 데이터에서 주성분(최대 분산 방향)을 SVD로 직접 구한다.

import numpy as np

rng = np.random.default_rng(0)
n = 300

# x, y가 강하게 상관되도록 만든 2D 데이터 (주된 퍼짐 방향이 대략 45도가 되게)
t = rng.normal(0, 3, n)
x = t + rng.normal(0, 0.3, n)
y = t * 0.6 + rng.normal(0, 0.3, n)
X = np.column_stack([x, y])  # shape (n, 2)

X_centered = X - X.mean(axis=0)  # PCA는 평균을 원점으로 옮긴 뒤 분산 방향을 찾는다

U, S, Vt = np.linalg.svd(X_centered, full_matrices=False)
print(f"특이값(Σ): {S}")
print("주성분 방향(V의 행, 분산이 큰 순서):\n", Vt)

pc1 = Vt[0]
angle_deg = np.degrees(np.arctan2(pc1[1], pc1[0]))
print(f"\n제1주성분(PC1) 방향 벡터 = {pc1}, x축 대비 각도 ≈ {angle_deg:.1f}도")

# 데이터를 PC1 축 하나에 투영 (2D -> 1D 차원축소)
projected = X_centered @ pc1
explained_var_ratio = (S ** 2) / np.sum(S ** 2)
print(f"\nPC1 하나로 설명되는 분산 비율 = {explained_var_ratio[0]:.4f}")
print(f"투영된 1D 값 예시(앞 5개): {np.round(projected[:5], 3)}")

연습

상관관계가 강한 2~3차원 합성 데이터를 만들어 중심화 후 SVD를 계산하고, 특이값의 제곱 비율로 각 주성분의 설명 분산을 구한 뒤 중심화를 생략했을 때 결과가 어떻게 달라지는지 비교해 보라.

실무 · Verex 연결

여러 마켓의 가격 시계열을 행렬로 놓고 주성분을 뽑으면 '시장 전체 방향' 같은 공통 요인과 개별 마켓 고유의 움직임을 분리할 수 있어, 이상 가격 감지나 리스크 집중도 파악에 쓸 수 있다.

공부한 날 원본 커리큘럼(docs/knowledge/math-50-curriculum.md)의 이 줄에 노트 링크와 ✅ 를 붙이면, 이 자리는 노트 본문으로 바로 이어집니다. 노트 없이 이 페이지에 바로 적어도 됩니다 — 다만 다시 생성하면 덮어쓰이므로, 남길 글은 docs/algorithms/ 의 마크다운으로 쓰는 편이 안전합니다.

← 22. 고유값/고유벡터24. 수치선형대수(조건수) →