Tech PostsTech Posts
기초와 계량경제학Basics & Econometrics · 06 / 24
06 기초와 계량경제학Basics & Econometrics

답이 이미 있는데 왜 반복해서 찾는가The Answer Already Exists, So Why Iterate Toward It?

OLS에는 닫힌 해가 있습니다. 그런데 그 해가 쓸 수 없게 되는 지점이 생각보다 빨리 옵니다.OLS has a closed-form solution. It stops being available sooner than you would expect.

OLS에는 닫힌 해가 있습니다. 답을 그냥 적어 내려갈 수 있고 모든 통계 패키지가 그렇게 직접 계산합니다. 그런데 왜 누군가는 선형회귀를 반복으로 추정할까요?

OLS has a closed-form solution. You can write the answer down, and every statistics package computes it directly. So why would anyone estimate a linear regression by iteration?

닫힌 해가 쓸 수 없게 되는 지점이 생각보다 빨리 오기 때문이고 반복하는 쪽이 현대 머신러닝 모형 거의 전부를 학습시키는 바로 그 알고리즘이기 때문입니다. 이 편은 둘 다 구현해서 비교합니다.

Because the closed form stops being available sooner than you would expect, and because the iterative alternative is the same algorithm that trains essentially every modern machine learning model. This post implements both and compares them.

닫힌 해The closed form

Y를 X에 회귀하는 단순회귀에서 최소제곱 추정치는 이렇습니다.

For a simple regression of Y on X, the least-squares estimates are:

β̂ = Σ(xᵢ − x̄)(yᵢ − ȳ) / Σ(xᵢ − x̄)² α̂ = ȳ − β̂ x̄

설계행렬 전체로 일반화하면 정규방정식이 됩니다.

In matrix form, with a full design matrix, this generalises to the normal equations.

β̂ = (XᵀX)⁻¹ Xᵀy

이건 정확합니다. 튜닝도, 수렴 기준도, 시작값도 없습니다. 데이터를 한 번 훑어 XᵀX와 Xᵀy를 만들고 풀면 끝입니다. 쓸 수 있을 때는 이게 옳은 선택이고 Statsmodels가 하는 일이 이것입니다.

This is exact. No tuning, no convergence criterion, no starting values — one pass through the data to build XᵀX and Xᵀy, then solve. When it is available it is the right choice, and it is what Statsmodels does.

쓸 수 없게 되는 세 지점Where it stops being available

정규방정식은 k × k 행렬을 만들고 역행렬을 구해야 합니다. k는 회귀변수 수입니다. 세 가지가 이것을 깹니다.

The normal equations require forming and inverting a k x k matrix, where k is the number of regressors. Three things break this.

  • k에 대한 비용. XᵀX를 만드는 건 O(nk²)이고 역행렬은 O(k³)입니다. k = 10이면 아무것도 아닙니다. 텍스트 피처, 상품마다의 고정효과, 원핫 인코딩된 고카디널리티 범주 때문에 k = 50,000이면 역행렬만으로 감당이 안 됩니다.
  • n에 대한 메모리. 닫힌 해는 설계행렬을 원합니다. 1억 행이면 RAM에 안 들어가고 데이터를 조각으로 먹을 수 있는 추정량이 필요합니다.
  • 비선형성. 모형이 모수에 선형이 아닌 순간 — 로지스틱 회귀, 신경망이 들어간 무엇이든 — 닫힌 해는 아예 없습니다. 반복이 유일한 선택지입니다.
  • Cost in k. Building XᵀX is O(nk²) and inverting it is O(k³). At k = 10 that is nothing. At k = 50,000 — text features, fixed effects for every product, one-hot encoded high-cardinality categories — the inversion alone is prohibitive.
  • Memory in n. The closed form wants the design matrix. At a hundred million rows it does not fit in RAM, and you need an estimator that can consume data in pieces.
  • Non-linearity. The moment the model is not linear in parameters — logistic regression, anything with a neural network in it — there is no closed form at all. Iteration is the only option.

경사하강이 하는 일How gradient descent works here

최소제곱은 잔차제곱합을 최소화합니다. 그 목적함수는 모수 공간에서 매끄러운 볼록 그릇이라 최솟값이 정확히 하나이고 국소 함정이 없습니다. 경사하강은 내리막을 걷습니다.

Least squares minimises the sum of squared residuals. That objective is a smooth convex bowl in the parameters, so it has exactly one minimum and no local traps. Gradient descent walks downhill.

  1. α와 β의 초깃값에서 시작합니다.
  2. 손실의 기울기를 계산합니다. 가장 가파르게 증가하는 방향입니다.
  3. 반대 방향으로 학습률만큼 이동합니다.
  4. 반복합니다.
  1. Start from a guess for α and β.
  2. Compute the gradient of the loss, the direction of steepest increase.
  3. Step in the opposite direction, scaled by a learning rate.
  4. Repeat.

확률적이라는 말은 기울기를 전체 데이터가 아니라 관측치 하나(또는 작은 배치)에서 계산한다는 뜻입니다. 각 걸음이 정확히 내리막이 아니라 대충 내리막이라 잡음이 섞이지만 비용이 O(nk)가 아니라 O(k)입니다. 걸음당 정밀도를 아주 많은 싼 걸음과 맞바꾸는 것이고 n이 크면 이 거래가 압도적으로 유리합니다.

The stochastic qualifier means the gradient is computed from one observation (or a small batch) rather than the whole dataset. Each step is therefore noisy — roughly downhill rather than exactly — but it costs O(k) instead of O(nk). You trade precision per step for a very large number of cheap steps, and on large n that trade is overwhelmingly worth it.

관측치 하나에 대한 갱신 규칙은 이게 전부입니다.

For a single observation, the update rules are the entire algorithm.

error = ŷ − y ŷ = α + βx α ← α − η · error β ← β − η · error · x
η는 학습률입니다. 나머지는 전부 이 두 줄 주위의 사무 처리입니다.η is the learning rate. Everything else is bookkeeping around these two lines.

둘을 나란히 놓기Putting them side by side

python
import numpy as np
import statsmodels.api as sm

rng = np.random.default_rng(3)
n = 5_000
x = rng.normal(size=n)
y = 1.5 + 2.5 * x + rng.normal(scale=0.5, size=n)

# --- closed form, via the normal equations
X = sm.add_constant(x)
exact = np.linalg.solve(X.T @ X, X.T @ y)

# --- stochastic gradient descent, written out
def sgd(x, y, eta=0.01, epochs=20, seed=0):
    rs = np.random.default_rng(seed)
    alpha, beta = 0.0, 0.0
    losses = []
    for _ in range(epochs):
        order = rs.permutation(len(x))        # shuffle each pass
        for i in order:
            error = (alpha + beta * x[i]) - y[i]
            alpha -= eta * error
            beta  -= eta * error * x[i]
        losses.append(np.mean(((alpha + beta * x) - y) ** 2))
    return alpha, beta, losses

alpha, beta, losses = sgd(x, y)

print(f"closed form : alpha={exact[0]:.4f}  beta={exact[1]:.4f}")
print(f"SGD         : alpha={alpha:.4f}  beta={beta:.4f}")
print(f"loss, first 3 epochs: {np.round(losses[:3], 4)}   final: {losses[-1]:.4f}")
같은 볼록 목적함수의 같은 최솟값으로 가는 두 경로입니다.Two routes to the same minimum of the same convex objective.
closed form : alpha=1.4966  beta=2.4968
SGD         : alpha=1.4966  beta=2.4967
loss, first 3 epochs: [0.2521 0.2519 0.2519]   final: 0.2519

소수점 몇 자리까지 일치합니다. 여기서 SGD는 OLS의 근사가 아닙니다. 같은 볼록 목적함수의 같은 최솟값으로 가는 다른 경로일 뿐입니다.

They agree to several decimal places. SGD is not an approximation to OLS here in any meaningful sense — it is a different route to the same minimum of the same convex objective.

차이는 어떻게 도달하느냐에 있고 그 차이가 볼 만합니다. 닫힌 해는 한 번에 답을 줍니다. 진단할 것이 없습니다. SGD는 궤적을 만듭니다. 손실을 반복 횟수에 대해 그리면 수렴했는지, 진동했는지, 발산했는지 알 수 있습니다. 그 그림이 앞으로 쓰게 될 모든 반복 적합 모형에서 주요 진단 도구가 됩니다.

The difference is in how they get there, and it is worth noticing. The closed form gives the answer in one shot, with nothing to diagnose. SGD produces a trajectory: plotting loss against iteration tells you whether it converged, oscillated or diverged — and that plot is the main diagnostic tool you have for every iteratively fitted model you will ever use.

학습률The learning rate

η는 반드시 골라야 하는 유일한 모수이고 양쪽으로 가혹합니다.

η is the one parameter you have to choose, and it is unforgiving in both directions.

  • 너무 작으면 수렴에 필요 이상으로 많은 패스가 듭니다.
  • 너무 크면 걸음이 최솟값을 넘어가고, 반복마다 오차가 커지며, 계수가 무한대나 NaN으로 발산합니다.
  • Too small and convergence takes far more passes than necessary.
  • Too large and the steps overshoot, the error grows each iteration, and the coefficients diverge to infinity or NaN.

실무에서In practice

  • 쓸 수 있으면 닫힌 해를 쓰십시오. 회귀변수가 감당할 만한 선형모형이라면 Statsmodels의 OLS가 정확하고 빠르며 표준오차·t값·진단까지 공짜로 줍니다. 메모리에 들어가는 문제에 SGD를 손으로 구현하는 건 연습이지 권고가 아닙니다.
  • 경사 기반 방법 전에 피처를 표준화하십시오. 실무에서 선택이 아닙니다. 스케일이 안 맞으면 손실 표면이 길고 좁은 계곡이 되고 경사하강은 계곡을 따라 내려가는 대신 가로질러 지그재그합니다.
  • 패스마다 섞으십시오. 데이터가 날짜·지역·결과 순으로 정렬되어 들어오면 순차 SGD가 구간마다 편향된 표본을 보고 모수가 정렬 순서를 따라 표류합니다. 에포크마다 섞으면 사라집니다.
  • 관측치 하나보다 미니배치를 쓰십시오. 32~256 크기 배치가 전체 배치 기울기의 분산 감소를 대부분 얻으면서 걸음당 비용을 낮게 유지하고 벡터화도 잘 됩니다. 순수한 한 개짜리 SGD는 주로 교육용입니다.
  • SGD가 주지 않는 것을 기억하십시오. Statsmodels가 표준오차를 주는 건 (XᵀX)⁻¹를 손에 쥐고 있기 때문입니다. SGD는 그 행렬을 계산하지 않으므로 손으로 짠 구현은 점추정치만 줍니다. 추론이 필요하면 닫힌 해를 쓰거나 부트스트랩하십시오. scikit-learn의 SGDRegressor도 마찬가지로 불확실성을 전혀 보고하지 않습니다.
  • Use the closed form when you can. For a linear model with a manageable number of regressors, Statsmodels OLS is exact, faster, and hands you standard errors, t-statistics and diagnostics for free. Hand-rolling SGD for a problem that fits in memory is an exercise, not a recommendation.
  • Standardise features before any gradient-based method. This is not optional in practice. Unscaled features produce an ill-conditioned loss surface — a long narrow valley — and gradient descent zig-zags across it instead of running down it.
  • Shuffle between passes. If the data arrive sorted by date, region or outcome, sequential SGD sees a biased sample in each stretch and the parameters drift with the ordering. Shuffling each epoch removes this.
  • Prefer mini-batches to single observations. Batches of 32-256 give most of the variance reduction of full-batch gradients while keeping the per-step cost low, and they vectorise well. Pure single-observation SGD is mainly of pedagogical interest.
  • Remember what SGD does not give you. Statsmodels returns standard errors because it has (XᵀX)⁻¹ in hand. SGD never computes that matrix, so a hand-rolled implementation gives point estimates and nothing else. If you need inference, use the closed form or bootstrap. Scikit-learn SGDRegressor likewise reports no uncertainty at all.

실제로 중요한 곳은 희소 피처가 수백만 개인 클릭 예측 모형, 추천 시스템, 디스크에서 스트리밍되는 데이터로 학습하는 모든 모형, 그리고 모든 신경망입니다. 각 경우에 닫힌 해는 존재하지 않거나 들어가지 않고 반복 버전만 남습니다. 그것이 방금 스무 줄로 쓴 절차와 같다는 것만 알아도 그 시스템들이 훨씬 덜 신비로워집니다.

Where this actually matters: click-through models with millions of sparse features, recommender systems, any model trained on data streamed off disk, and every neural network. In each case the closed form does not exist or does not fit, and the iterative version is the only one available. Knowing it is the same procedure you just wrote in twenty lines makes those systems considerably less mysterious.

여기까지 이 시리즈의 모든 모형은 올바르게 설정되어 있었습니다. 데이터를 우리가 만들고 그에 맞는 형태를 적합했습니다. 다음 편은 그 가정을 일부러 깹니다.

So far every model in this series has been correctly specified — we generated the data and then fitted the matching form. The next post breaks that assumption deliberately.