SVD, QR 및 촐레스키 분해
차원 축소와 인수분해에 svd(), qr(), chol()을 적용합니다.
SVD, QR 및 촐레스키 분해은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
행렬 분해가 필요한 이유
행렬 분해는 A를 더 단순한 행렬들의 곱으로 인수분해합니다. 숨겨진 구조(랭크, 조건)를 드러내고 효율적인 계산을 가능하게 하며, 통계학과 기계 학습에서 PCA, 회귀 및 최적화의 기반이 됩니다.
# Three fundamental decompositions:
# 1. SVD: A = U D V' (any matrix)
# 2. QR: A = Q R (any matrix)
# 3. Cholesky: A = L L' (symmetric positive definite)
# Each serves a purpose:
# SVD -> PCA, pseudoinverse, rank, image compression
# QR -> linear regression, Gram-Schmidt, eigenvalues
# Cholesky -> fast solve for SPD systems, simulation
A <- matrix(c(4, 3, 2,
3, 6, 1,
2, 1, 5), nrow = 3, byrow = TRUE)
cat('Matrix ready for decomposition')
print(A)SVD: svd() 함수
특이값 분해(SVD)는 임의의 m×n 행렬을 A = U D V'로 인수분해합니다. 여기서 U와 V는 직교 행렬이고 D는 감소하는 순서의 음이 아닌 특이값을 갖는 대각 행렬입니다.
A <- matrix(c(1, 2, 3,
4, 5, 6), nrow = 2, byrow = TRUE)
# Compute SVD
svd_result <- svd(A)
# Components:
svd_result$d # singular values (decreasing)
svd_result$u # left singular vectors (2x2)
svd_result$v # right singular vectors (3x2)
cat('Singular values:', svd_result$d, '\n')
cat('Rank of A:', sum(svd_result$d > 1e-10), '\n')SVD 재구성
SVD에서 A를 A = U %*% diag(d) %*% t(V)로 재구성합니다. 저랭크 근사는 상위 k개의 특이값과 특이벡터만 유지하며, 이는 이미지 압축과 잡음 감소의 기반입니다.
A <- matrix(c(1, 2, 3,
4, 5, 6,
7, 8, 9), nrow = 3, byrow = TRUE)
res <- svd(A)
U <- res$u; d <- res$d; V <- res$v
# Full reconstruction: A = U diag(d) V'
A_reconstructed <- U %*% diag(d) %*% t(V)
all.equal(A, A_reconstructed) # TRUE
# Rank-1 approximation (best rank-1 approx by Eckart-Young)
A_rank1 <- d[1] * U[, 1] %*% t(V[, 1])
print(round(A_rank1, 2))
# Frobenius error of rank-1 approx
sqrt(sum((A - A_rank1)^2))SVD: 의사역행렬과 랭크
SVD는 의사역행렬 A⁺ = V D⁺ U'를 제공합니다. 여기서 D⁺는 0이 아닌 각 특이값을 그 역수로 바꾼 행렬입니다. A가 정사각 행렬이 아니거나 최대 랭크가 아니더라도 최소제곱의 의미에서 Ax = b를 풉니다.
A <- matrix(c(1, 2, 3,
4, 5, 6), nrow = 2, byrow = TRUE)
# Pseudoinverse via SVD
svd_res <- svd(A)
tol <- 1e-10
# Invert nonzero singular values
d_inv <- ifelse(svd_res$d > tol, 1/svd_res$d, 0)
A_pinv <- svd_res$v %*% diag(d_inv) %*% t(svd_res$u)
print(A_pinv) # 3x2 pseudoinverse
# Least-squares solution: x = A+ b
b <- c(7, 8)
x_ls <- A_pinv %*% b
print(x_ls)
# Compare with MASS::ginv
# MASS::ginv(A) should give the same resultQR 분해: qr()
QR 분해는 A = QR로 인수분해합니다. 여기서 Q는 직교 행렬(Q'Q = I)이고 R은 상삼각 행렬입니다. QR 분해는 선형 회귀, 고유값 계산(QR 알고리즘), 그람-슈미트 직교화에 사용됩니다.
A <- matrix(c(1, 2,
3, 4,
5, 6), nrow = 3, byrow = TRUE)
# Compute QR decomposition
qr_res <- qr(A)
# Extract Q and R
Q <- qr.Q(qr_res) # 3x2 orthogonal
R <- qr.R(qr_res) # 2x2 upper triangular
cat('Q is orthogonal: Q\'Q = I\n')
print(round(t(Q) %*% Q, 10)) # Identity
cat('R is upper triangular:\n')
print(round(R, 6))
# Reconstruct A = Q %*% R
all.equal(A, Q %*% R) # TRUE회귀를 위한 QR
QR을 통해 선형 회귀의 정규방정식을 푸는 방법은 수치적으로 더 우수합니다. Q'Q = I이므로 정규방정식 A'Ax = A'b는 R'Q'QRx = R'Q'b가 되고, Rx = Q'b로 단순화되어 후진 대입으로 풀 수 있습니다.
# Generate regression data
set.seed(7)
n <- 20
x1 <- rnorm(n); x2 <- rnorm(n)
y <- 1 + 2*x1 - 0.5*x2 + rnorm(n, sd = 0.5)
# Design matrix
X <- cbind(intercept = 1, x1 = x1, x2 = x2)
# QR solve: numerically stable
beta_qr <- qr.solve(X, y)
print(beta_qr) # ~c(1, 2, -0.5)
# Compare with lm()
beta_lm <- coef(lm(y ~ x1 + x2))
all.equal(beta_qr, beta_lm, check.names = FALSE) # TRUE
# The qr.solve internals use backsolve on R
cat('QR regression is lm()\'s default method')촐레스키 분해: chol()
촐레스키 분해는 대칭 양의 정부호 행렬을 A = L L'로 인수분해합니다. 여기서 L은 하삼각 행렬입니다. R의 chol()은 상삼각 인수 U를 반환하므로 A = t(U) %*% U입니다.
# Symmetric positive definite matrix
A <- matrix(c(4, 2,
2, 3), nrow = 2, byrow = TRUE)
# Cholesky decomposition: A = t(U) %*% U
U <- chol(A)
print(U)
# Note: chol() returns UPPER triangular in R
# Reconstruct
all.equal(A, t(U) %*% U) # TRUE
# Attempting Cholesky on non-PD matrix throws error
# Catch it:
result <- tryCatch(
chol(matrix(c(1, 3, 3, 2), nrow = 2)),
error = function(e) cat('Error:', e$message)
)촐레스키 분해로 풀기
대칭 양의 정부호 시스템(공분산 행렬 등)에서는 촐레스키 기반 해법이 LU보다 두 배 빠릅니다. 역행렬을 계산하려면 chol2inv()를 사용하거나, 촐레스키 인수와 함께 backsolve/forwardsolve를 사용하세요.
# SPD system: typical in statistics (covariance matrices)
set.seed(1)
X <- matrix(rnorm(30), nrow = 10, ncol = 3)
A <- crossprod(X) # X'X is always SPD
b <- c(1, 2, 3)
# Cholesky factor
U <- chol(A) # Upper triangular
# Solve A x = b using two triangular solves
# A = t(U) %*% U -> solve t(U) y = b, then U x = y
y <- forwardsolve(t(U), b)
x <- backsolve(U, y)
print(x)
# Verify
all.equal(as.vector(A %*% x), b)
# Or: inverse via chol2inv
A_inv <- chol2inv(U)
all.equal(x, as.vector(A_inv %*% b))PCA에서의 SVD
SVD를 통한 PCA에서는 데이터 행렬 X를 중심화한 다음 중심화된 X의 SVD를 계산합니다. 오른쪽 특이벡터 V는 주성분 방향이고, 특이값 d는 설명되는 분산과 관련됩니다(d²/(n-1)).
set.seed(42)
n <- 50; p <- 3
X <- matrix(rnorm(n * p), nrow = n)
# Add correlation
X[, 2] <- 0.8 * X[, 1] + 0.6 * X[, 2]
# Center
X_c <- scale(X, center = TRUE, scale = FALSE)
# SVD of centered data
svd_res <- svd(X_c)
# Variance explained by each PC
var_explained <- svd_res$d^2 / (n - 1)
prop_var <- var_explained / sum(var_explained)
cat('Proportion of variance explained:\n')
print(round(prop_var, 3))
# Compare with prcomp
pc <- prcomp(X)
all.equal(prop_var, pc$sdev^2 / sum(pc$sdev^2))SVD를 통한 행렬 랭크
행렬의 랭크는 무시할 수 없을 정도로 큰 특이값의 개수와 같습니다. SVD는 랭크를 결정하는 가장 수치적으로 신뢰할 수 있는 방법을 제공합니다. 일반적으로 max(d) * tol을 기준으로 하여 그보다 큰 d 값의 개수를 세면 됩니다.
# Full-rank matrix (rank 3)
A <- matrix(c(1, 0, 0,
0, 2, 0,
0, 0, 3), nrow = 3)
svd(A)$d # c(3, 2, 1) - all nonzero -> rank 3
# Rank-deficient matrix (rank 2)
B <- matrix(c(1, 2, 3,
2, 4, 6, # row 2 = 2 * row 1
0, 1, 1), nrow = 3, byrow = TRUE)
svd(B)$d # Third value is ~0
# Rank function using SVD
matrix_rank <- function(M, tol = 1e-10) {
d <- svd(M)$d
sum(d > tol * d[1]) # relative tolerance
}
matrix_rank(B) # 2다변량 정규분포 표본 추출을 위한 촐레스키 분해
다변량 정규분포 N(μ, Σ)에서 표본을 추출하려면 Σ의 촐레스키 인수 U를 계산한 다음 표준 정규 변수를 변환합니다: X = μ + Z %*% U. 이것이 MASS::mvrnorm()이 내부적으로 작동하는 방식입니다.
set.seed(99)
# Covariance matrix
Sigma <- matrix(c(4, 2,
2, 3), nrow = 2)
mu <- c(1, 5)
n_samples <- 500
# Cholesky factor
U <- chol(Sigma)
# Sample standard normals
Z <- matrix(rnorm(n_samples * 2), nrow = n_samples)
# Transform: X ~ N(mu, Sigma)
X <- sweep(Z %*% U, 2, mu, FUN = '+')
# Check empirical covariance
print(round(cov(X), 2)) # Should be close to Sigma
print(round(colMeans(X), 2)) # Should be close to mu빠른 확인
R의 SVD, QR 및 촐레스키 분해에 대한 이해도를 확인해 보세요.
복습: SVD, QR 및 촐레스키 분해
핵심 요점: SVD(svd())는 d, u, v를 반환하며 PCA, 랭크, 의사역행렬 및 저랭크 근사에 사용됩니다. QR(qr())은 직교 행렬 Q와 상삼각 행렬 R을 반환하며 회귀와 안정성에 사용됩니다. 촐레스키 분해(chol())는 A = t(U)%*%U를 만족하는 상삼각 행렬 U를 반환하며, SPD 시스템에서 가장 빠릅니다. 세 분해는 모두 A를 정확히 재구성하지만 서로 다른 계산 목적에 사용됩니다.
A <- matrix(c(4, 2, 2, 3), nrow = 2)
# SVD
res <- svd(A)
all.equal(A, res$u %*% diag(res$d) %*% t(res$v)) # TRUE
# QR (on a design matrix)
X <- cbind(1, c(1,2,3,4,5))
qr_res <- qr(X)
all.equal(X, qr.Q(qr_res) %*% qr.R(qr_res)) # TRUE
# Cholesky
U <- chol(A)
all.equal(A, t(U) %*% U) # TRUE
# Use cases:
# svd() -> PCA, rank, pseudoinverse
# qr() -> regression, stability
# chol()-> SPD solve, MVN sampling자주 묻는 질문
“SVD, QR 및 촐레스키 분해” 강의는 무료인가요?
네 — “SVD, QR 및 촐레스키 분해” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“SVD, QR 및 촐레스키 분해”에서 뭘 배우나요?
차원 축소와 인수분해에 svd(), qr(), chol()을 적용합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
R Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“SVD, QR 및 촐레스키 분해” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 행렬 곱셈과 행렬식
- solve()로 연립 선형 방정식 풀기
- 고유값과 고유벡터
- SVD, QR 및 촐레스키 분해