능형회귀 보기¶
개요¶
능형회귀는 최소제곱(OLS) 목적함수에 \(L_2\) 벌점을 더해 계수를 0 쪽으로 축소하되 어느 것도 정확히 0으로 만들지는 않는다. 이 기법은 설명변수들이 상관되어 있거나(다중공선성) \(p\)가 \(n\)에 가깝거나 그보다 클 때 특히 효과적이다. 이 절에서는 능형 추정량을 유도하고, 편향-분산 절충을 살펴보며, 조율모수 \(\lambda\)가 계수 추정치에 미치는 영향을 확인한다.
능형 목적함수¶
계획행렬 \(X \in \mathbb{R}^{n \times p}\)와 반응변수 \(y \in \mathbb{R}^n\)이 주어졌을 때 능형회귀 문제는
이며, 여기서 \(\lambda \ge 0\)은 정칙화(조율) 모수다. 벌점항 \(\lambda \| \beta \|_2^2 = \lambda \sum_{j=1}^{p} \beta_j^2\)는 계수가 커지는 것을 억제한다.
닫힌 형태의 해¶
기울기를 0으로 놓으면 닫힌 형태의 해
를 얻는다. \(\lambda = 0\)이면 OLS 추정량이 되고, \(\lambda \to \infty\)이면 모든 계수가 0으로 축소된다.
편향-분산 절충¶
능형회귀는 편향을 감수하는 대신 분산을 줄인다. 능형 추정량의 평균제곱오차(MSE)는
으로 분해된다. \(\lambda\)가 작으면 추정량은 거의 불편이지만 분산이 크고(OLS에 가깝다), \(\lambda\)가 크면 분산은 작지만 편향이 크다. 최적의 \(\lambda\)는 둘의 합인 MSE를 최소화한다.
코드: 자료 생성과 능형 적합¶
\(\lambda\)를 키워 가며 계수가 어떻게 줄어드는지, 그리고 참값과의 거리가 어디에서 가장 작아지는지를 본다.
보기 1. 람다에 따른 축소와 편향-분산 절충. \(n = 40\), \(p = 20\)이고 참 계수는 앞의 셋만 \((3, -2, 1.5)\)이며 잡음은 \(N(0,1)\)이다. \(X\)를 고정해 놓고 \(\lambda\)를 키워 간다.
(1) \(\lVert\hat\beta^{\text{ridge}}(\lambda)\rVert_2\)가 \(\lambda\)에 대해 반드시 감소함을 특이값분해로 보이시오. 참값과의 거리도 그러한가.
(2) \(E\lVert\hat\beta(\lambda) - \beta\rVert^2\)를 편향과 분산으로 나누어 적고, \(\lambda = 0\)에서의 도함수를 구해 최소제곱보다 나은 \(\lambda > 0\)이 반드시 존재함을 보이시오. 그 값을 코드로 확인하시오.
풀이
(1) 해석적으로. \(X = UDV^\top\)를 특이값분해라 하면 (연습문제 2에서 유도하듯)
이고 \(v_j\)가 정규직교이므로
이다. 각 항의 분모가 \(\lambda\)에 대해 증가하므로 모든 항이 따로따로 감소한다. 합도 감소한다. 여기에 U자가 생길 수 없으며, 이것은 자료와 무관한 항등식 수준의 사실이다.
참값과의 거리는 다르다. \(\lambda\)가 크면 \(\hat\beta \to 0\)이고 거리는 \(\lVert\beta\rVert = \sqrt{9+4+2.25} = 3.9051\)로 올라가므로, 거리가 끝까지 줄어들 수는 없다. (2)에서 보듯 중간에 바닥이 있다.
(2) 해석적으로. \(S = X^\top X\), \(A_\lambda = (S+\lambda I)^{-1}\)이라 두자. \(X\)를 고정하면 \(\hat\beta = A_\lambda X^\top y\)이고 \(y = X\beta + \varepsilon\), \(\operatorname{Var}(\varepsilon) = \sigma^2 I\)이므로
이다. 마지막 등식은 \(A_\lambda S - I = A_\lambda(S + \lambda I - \lambda I) - I = -\lambda A_\lambda\)에서 나온다. 분산 쪽은 \(\operatorname{Var}(\hat\beta) = \sigma^2 A_\lambda S A_\lambda\)이므로
다. \(\lambda = 0\)에서 값은 \(\sigma^2\operatorname{tr}(S^{-1})\)으로 최소제곱의 오차다.
이제 \(\lambda = 0\)에서의 도함수를 본다. 편향항은 \(\lambda^2\)에 비례하므로 미분하면 \(2\lambda(\cdots)\) 꼴이라 \(\lambda = 0\)에서 0이다. 분산항은 \(\frac{d}{d\lambda}A_\lambda = -A_\lambda^2\)이므로
이다. 편향은 이차로 자라고 분산은 일차로 줄어든다. 그러므로 \(\lambda = 0\) 바로 오른쪽에서 오차가 반드시 감소하며, 최소제곱보다 나은 \(\lambda > 0\)이 언제나 존재한다. 이것이 능형회귀의 존재정리이고, 이 보기의 표에서 \(\lambda = 1\)이 \(\lambda = 0\)을 이기는 까닭이다.
(2) 수치적으로.
import numpy as np
from sklearn.linear_model import LinearRegression, Ridge
rng = np.random.default_rng(42)
# 설명변수 20개 중 참으로 쓰이는 것은 앞의 셋뿐이다. 관측은 40개로 변수 수에
# 비해 적어, 최소제곱이 잡음까지 따라가기 좋은 상황이다.
n, p = 40, 20
X = rng.normal(size=(n, p))
beta_true = np.zeros(p)
beta_true[:3] = [3.0, -2.0, 1.5]
y = X @ beta_true + rng.normal(0, 1, n)
ols = LinearRegression().fit(X, y)
# lambda 를 키울수록 계수가 0 쪽으로 줄어든다. 라쏘와 달리 정확히 0 이 되지는
# 않고 작아지기만 한다. 그래서 능형은 변수를 고르지 못한다.
print(f"{'lambda':>8} {'계수의 L2 크기':>14} {'참값과의 거리':>14}")
print(f"{0.0:>8.1f} {np.linalg.norm(ols.coef_):>14.3f} "
f"{np.linalg.norm(ols.coef_ - beta_true):>14.3f}")
for lam in [0.1, 1.0, 10.0, 100.0]:
ridge = Ridge(alpha=lam).fit(X, y)
print(f"{lam:>8.1f} {np.linalg.norm(ridge.coef_):>14.3f} "
f"{np.linalg.norm(ridge.coef_ - beta_true):>14.3f}")
# 참값과의 거리가 lambda=0 일 때보다 중간 어딘가에서 작아진다. 편향을 조금
# 받아들이는 대가로 분산을 크게 줄인 결과이며, 이것이 편향-분산 절충이다.
# --- 유도한 기댓값 곡선과 맞춰 본다 (sigma = 1, X 는 고정) ---
S = X.T @ X
def expected_sq_error(lam):
"""E||beta_hat(lam) - beta||^2 = 편향^2 + 분산. X 를 고정한 조건부 기댓값."""
A = np.linalg.inv(S + lam * np.eye(p))
bias2 = lam ** 2 * beta_true @ (A @ A) @ beta_true
var = np.trace(A @ S @ A)
return bias2, var
lams = np.logspace(-2, 2, 400)
tot = np.array([sum(expected_sq_error(l)) for l in lams])
k = tot.argmin()
b2, v = expected_sq_error(lams[k])
print(f"이론: lambda = 0 에서 E||.||^2 = tr(S^-1) = {np.trace(np.linalg.inv(S)):.4f}")
print(f"이론: 최솟값 {tot[k]:.4f} (편향^2 {b2:.4f} + 분산 {v:.4f}) at lambda = {lams[k]:.4f}")
print(f"0 에서의 도함수 = -2*tr(S^-2) = {-2 * np.trace(np.linalg.inv(S) @ np.linalg.inv(S)):.4f} (< 0)")
grid = np.logspace(-2, 2, 2000)
dist = np.array([np.linalg.norm(Ridge(alpha=l).fit(X, y).coef_ - beta_true) for l in grid])
print(f"이 표본의 거리 곡선 최솟값 {dist.min():.4f} at lambda = {grid[dist.argmin()]:.4f}")
출력:
lambda 계수의 L2 크기 참값과의 거리
0.0 4.202 1.081
0.1 4.169 1.048
1.0 3.929 0.880
10.0 2.891 1.404
100.0 1.091 3.026
이론: lambda = 0 에서 E||.||^2 = tr(S^-1) = 1.3683
이론: 최솟값 1.0621 (편향^2 0.1914 + 분산 0.8707) at lambda = 1.6810
0 에서의 도함수 = -2*tr(S^-2) = -0.5116 (< 0)
이 표본의 거리 곡선 최솟값 0.8499 at lambda = 1.7584

유도와 코드가 맞는다. 기댓값 곡선은 \(\lambda = 1.6810\)에서 바닥을 치고, 이 한 표본의 거리 곡선은 \(\lambda = 1.7584\)에서 바닥을 친다. 둘이 정확히 같을 이유는 없다. 앞의 것은 \(y\)에 대한 기댓값이고 뒤의 것은 \(y\)를 한 번 뽑은 실현값이기 때문이다. 바닥의 위치가 가까운 것으로 충분하며, 바닥의 값은 \(1.0305\)(기댓값의 제곱근) 대 \(0.8499\)로 더 벌어진다. 이 표본이 운 좋게 평균보다 잘 맞은 것이다.
\(\lambda = 0\)에서의 도함수가 \(-0.5116\)으로 음수인 것이 (2)의 결론을 그대로 확인한다. 최적점에서 편향제곱 \(0.1914\)와 분산 \(0.8707\)의 합 \(1.0621\)이 최소제곱의 \(1.3683\)보다 \(22\%\) 작다. 편향 \(0.19\)를 사서 분산 \(0.50\)을 깎은 거래다.
위 표의 다섯 줄을 촘촘한 격자로 채워 그린 것이 위 그림이다. 파란 곡선은 계수벡터의 크기 \(\lVert\hat{\boldsymbol{\beta}}\rVert_2\), 주황 곡선은 참값과의 거리 \(\lVert\hat{\boldsymbol{\beta}} - \boldsymbol{\beta}\rVert_2\)다. 두 곡선의 모양이 다르다는 것이 이 그림의 전부다.
파란 곡선은 끝까지 단조감소한다. \(4.202\)에서 출발해 \(\lambda = 100\)에서 \(1.091\)까지, 그리고 그 뒤로도 계속 내려간다. (1)에서 항별로 보인 그대로이며 여기에는 U자가 있을 수 없다.
주황 곡선은 다르다. \(\lambda = 0.01\)에서 \(1.081\)(OLS와 사실상 같다)로 시작해 \(\lambda = 1.76\)에서 \(0.850\)까지 내려갔다가 다시 올라간다. \(\lambda = 10\)에서 벌써 \(1.404\)로 OLS보다 나빠지고 \(\lambda = 100\)에서는 \(3.026\)이다. 회색 점선으로 그린 OLS 수준 \(1.081\)과 주황 곡선이 만나는 지점이 \(\lambda = 5.51\)인데, 그보다 큰 \(\lambda\)는 손해라는 뜻이다. 이득이 나는 구간은 생각보다 좁다.
여기서 실무적 함정 하나가 보인다. 계수가 작아지는 것은 눈에 잘 띄지만 정확도가 나빠지는 것은 눈에 띄지 않는다. \(\lambda = 100\)에서 계수의 크기는 \(1.091\)로 "아주 깔끔하게 정리된" 모형처럼 보이는데, 실제로는 참값에서 \(3.026\)만큼 떨어져 OLS보다 세 배 나쁘다. 계수가 작다는 것은 좋은 모형의 증거가 아니다. 어디가 바닥인지는 오직 자료로 추정해야 하며, 그 방법이 교차검증이다.
표준화¶
\(L_2\) 벌점은 모든 계수를 동등하게 취급하므로, 적합 전에 설명변수를 표준화해야 한다.
여기서 \(\bar{x}_j\)와 \(s_j\)는 \(j\)번째 설명변수의 표본평균과 표본표준편차다. 표준화하지 않으면 벌점이 단위가 큰 변수의 계수를 부당하게 더 많이 축소한다.
정칙화 경로¶
정칙화 경로는 각 계수 \(\hat{\beta}_j^{\text{ridge}}\)를 \(\lambda\)(또는 \(\log_{10}\lambda\))의 함수로 그린 그림이다. 주요 관찰 사항은 다음과 같다.
- 유한한 모든 \(\lambda\)에 대해 계수는 0이 아니다.
- \(\lambda\)가 커짐에 따라 계수는 매끄럽게 0을 향해 축소된다.
- 중요한 설명변수의 계수는 더 넓은 \(\lambda\) 범위에서 큰 값을 유지한다.
해석¶
- 능형회귀는 변수선택을 하지 않는다. \(\lambda\)와 무관하게 모든 설명변수가 모형에 남는다. 희소성을 통한 해석 가능성이 필요하면 라쏘나 엘라스틱넷을 고려하라.
- 다중공선성 완화. \(X^\top X\)에 더해지는 \(\lambda I_p\)가 행렬의 가역성을 보장하고 추정치를 안정화한다.
- \(\lambda\)의 선택. 교차검증(예: 5-겹 또는 10-겹)이 표준적인 방법이다. 교차검증 예측오차를 최소화하는 \(\lambda\)를 고른다.
연습문제¶
연습문제 1. 능형 목적함수에서 출발하여 기울기를 0으로 놓음으로써 닫힌 형태의 해 \(\hat{\beta}^{\text{ridge}} = (X^\top X + \lambda I_p)^{-1} X^\top y\)를 유도하라.
풀이
목적함수는
이다. 전개한 뒤 \(\beta\)로 미분하면
이고, 이를 0으로 놓으면
를 얻는다. \(\lambda > 0\)이면 \(X^\top X + \lambda I_p\)는 양정치이므로 가역이고, 따라서
연습문제 2. \(X = U D V^\top\)를 특이값분해(SVD)라 할 때, 능형 추정량이 \(\hat{\beta}^{\text{ridge}} = \sum_{j=1}^{p} \frac{d_j^2}{d_j^2 + \lambda}\, \frac{u_j^\top y}{d_j}\, v_j\) 로 표현됨을 보여라.
풀이
\(X = U D V^\top\)이고 \(D = \text{diag}(d_1, \dots, d_p)\)라 하자. 그러면 \(X^\top X = V D^2 V^\top\), \(X^\top y = V D U^\top y\)이므로
이다. 성분으로 쓰면 \(V^\top \hat{\beta}^{\text{ridge}}\)의 \(j\)번째 원소가 \(\frac{d_j}{d_j^2 + \lambda} u_j^\top y\)이므로
를 얻는다. 인자 \(d_j^2 / (d_j^2 + \lambda) \in [0, 1)\)은 특이값이 작은 방향을 더 강하게 축소한다. \(\square\)
연습문제 3. \(X^\top X = I_p\)(정규직교 계획)라 하자. \(\hat{\beta}_j^{\text{ridge}}\)를 \(\hat{\beta}_j^{\text{OLS}}\)와 \(\lambda\)로 표현하라.
풀이
\(X^\top X = I_p\)이면 OLS 추정량은 \(\hat{\beta}^{\text{OLS}} = X^\top y\)이고, 능형 추정량은
이 된다. 즉 모든 계수가 \(1/(1 + \lambda)\)배로 균일하게 축소된다. 이는 능형회귀가 비례 축소를 수행함을 확인해 준다. \(\square\)
연습문제 4. 다중공선성이 있는 인공자료(\(n = 200\), \(p = 10\))에 대해 5-겹 교차검증으로 격자 \(\lambda \in \{10^{-3}, 10^{-2}, \dots, 10^{3}\}\)에서 최적 \(\lambda\)를 찾아라. 최적 \(\lambda\)의 교차검증 RMSE를 보고하고 OLS의 RMSE와 비교하라.
풀이
import numpy as np
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
np.random.seed(42)
n, p = 200, 10
# 상관된 설계행렬
rho = 0.9
Sigma = rho * np.ones((p, p)) + (1 - rho) * np.eye(p)
L = np.linalg.cholesky(Sigma)
X = np.random.randn(n, p) @ L.T
beta_true = np.array([3, -2, 1.5, 0, 0, 0, 0, 0, 0, 0])
y = X @ beta_true + np.random.randn(n)
scaler = StandardScaler()
X_s = scaler.fit_transform(X)
# OLS
ols_scores = cross_val_score(
LinearRegression(), X_s, y, cv=5,
scoring="neg_mean_squared_error"
)
ols_rmse = np.sqrt(-ols_scores.mean())
# 능형회귀의 격자탐색
best_rmse, best_lam = np.inf, None
for exp in range(-3, 4):
lam = 10.0 ** exp
scores = cross_val_score(
Ridge(alpha=lam), X_s, y, cv=5,
scoring="neg_mean_squared_error"
)
rmse = np.sqrt(-scores.mean())
if rmse < best_rmse:
best_rmse, best_lam = rmse, lam
print(f"OLS CV RMSE: {ols_rmse:.4f}")
print(f"Best lambda: {best_lam}")
print(f"Ridge CV RMSE: {best_rmse:.4f}")
출력:
OLS CV RMSE: 1.0171
Best lambda: 1.0
Ridge CV RMSE: 1.0156
실행하면 OLS의 교차검증 RMSE는 1.0171이고, 최적 \(\lambda = 1\)에서 능형회귀의 RMSE는 1.0156으로 조금 더 작다. \(\lambda\)를 더 키우면(10, 100, 1000) RMSE는 각각 1.0768, 1.4158, 1.7891로 오히려 나빠진다. 즉 정칙화는 도움이 되지만 그 이득의 크기와 최적 \(\lambda\)의 위치는 자료에 따라 다르며, 여기서는 \(n = 200\)이 \(p = 10\)에 비해 충분히 커서 OLS 자체가 이미 안정적이므로 개선폭이 작다. 개선폭은 \(p/n\)이 커질수록 뚜렷해진다. \(\square\)
연습문제 5. 임의의 \(\lambda > 0\)에 대해 능형 추정량이 \(\|\hat{\beta}^{\text{ridge}}\|_2 \le \|\hat{\beta}^{\text{OLS}}\|_2\)를 만족함을 증명하라.
풀이
KKT 조건에 의해 능형 문제는 어떤 \(t > 0\)에 대해
와 동치다. OLS 해는 아무 제약 없이 손실을 최소화하므로, \(\hat{\beta}^{\text{OLS}}\)는 제약영역 안에 있거나(이 경우 \(\hat{\beta}^{\text{ridge}} = \hat{\beta}^{\text{OLS}}\)이고 등호가 성립한다) 밖에 있다. 밖에 있으면 제약 최적해는 경계 \(\|\beta\|_2^2 = t < \|\hat{\beta}^{\text{OLS}}\|_2^2\) 위에 놓인다. 어느 경우든
정리하며¶
능형회귀를 실제로 적합해 보았다.
- \(\lambda\) 를 키우면 모든 계수가 \(0\) 쪽으로 모인다. 정칙화 경로를 그리면 그 수축이 한눈에 보이며, 어느 것도 \(0\) 에 닿지 않는다.
- 상관된 설명변수들을 비슷한 크기로 나눠 갖는다. 라쏘가 하나를 고르고 나머지를 버리는 것과 대조되며, 공선 집단을 다룰 때 능형이 안정적인 이유다.
- \(p>n\) 에서도 작동한다. OLS 가 아예 정의되지 않는 상황에서 해를 준다.
- \(\lambda\) 선택이 남은 문제다. 교차검증으로 고르며, 이 장 뒤에서 다룬다.
- 계수를 효과크기로 읽으면 안 된다. 축소되어 있으므로 체계적으로 과소평가하며, 예측이 목적일 때 쓰는 도구다(1장의 예측 대 추론).
다음 절 라쏘의 베이즈 해석으로 넘어간다.