Y와 X 데이터가 있습니다. 이론상 똑같이 그럴듯한 후보가 둘입니다. 하나는 X에 선형이고 하나는 log X에 선형입니다. 표본 내 적합도로는 신뢰할 만하게 가릴 수 없습니다. 어떻게 고를까요?
You have data on Y and X. Two candidates fit the story equally well in theory — one linear in X, one linear in log X. In-sample fit will not settle it reliably. How do you choose?
교차검증은 모형이 이미 본 데이터로 채점받는 것을 거부함으로써 답합니다.
Cross-validation answers this by refusing to grade a model on data it has already seen.
문제를 정확히 놓기Stating the problem precisely
Y와 X의 쌍이 관측되고 자료생성과정이 어느 쪽인지 모릅니다.
We observe pairs of Y and X, and do not know which data-generating process holds.
Y = α + β X + ε 또는 / or Y = α + β log(X) + ε둘 다 적합해서 R²를 비교하고 싶어집니다. 이건 실패하고, 체계적으로 실패합니다. R²는 유연성을 더할수록 절대 줄지 않으므로 비교가 자유도가 큰 쪽으로 기웁니다. 잔차제곱합은 이 표본에 얼마나 잘 맞췄는지를 잽니다. 거기에는 우연이었던 부분까지 들어갑니다.
The temptation is to fit both and compare R². This fails, and fails systematically: R² never decreases when you add flexibility, so the comparison is biased toward whichever specification has more freedom to chase noise. The residual sum of squares measures how well you fitted this sample, including the parts of it that were random.
실제로 알고 싶은 것은 한 번도 본 적 없는 관측치를 어느 쪽이 더 잘 예측하느냐입니다. 다른 질문이고 모형이 건드리지 않은 데이터가 필요합니다.
What you actually want to know is which specification predicts observations it has never seen. That is a different question, and it needs data the model has not touched.
하나만 빼기Leave one out
LOOCV는 가장 단순한 정직한 답입니다. i = 1..N 각각에 대해:
LOOCV is the simplest honest answer. For each observation i in 1..N:
- i를 제외한 모든 관측치로 모형을 추정합니다. i에 대한 지식이 전혀 없는 모수가 나옵니다.
- 그 모형으로 관측치 i의 Y를 예측합니다.
- 오차를 기록합니다.
- Estimate the model on all observations except i, giving parameters fitted without any knowledge of i.
- Use that fitted model to predict Y for observation i.
- Record the error.
N번 돌고 나면 모든 관측치를 자신을 본 적 없는 모형이 정확히 한 번씩 예측한 셈입니다. 오차를 모아 제곱근평균으로 만듭니다.
After N passes, every observation has been predicted exactly once by a model that never saw it. Aggregate the errors into a root mean square.
RMSE = sqrt( (1/N) · Σ (Y_i − Ŷ_i)² )어느 설정이든 LOOCV RMSE가 낮은 쪽이 더 나은 예측자입니다. 자신을 예측하는 모형에 어떤 관측치도 기여하지 않으므로 비교가 유연성 쪽으로 기울지 않습니다.
Whichever specification produces the lower LOOCV RMSE is the better predictor. Because no observation ever contributes to the model that predicts it, the comparison is not rigged toward flexibility.
import numpy as np
import statsmodels.api as sm
from sklearn.model_selection import LeaveOneOut
rng = np.random.default_rng(1)
n = 200
X = rng.uniform(1, 20, n)
Y = 2.0 + 3.0 * np.log(X) + rng.normal(scale=1.0, size=n) # truth is log
def loocv_rmse(design):
errors = []
for train, test in LeaveOneOut().split(design):
fit = sm.OLS(Y[train], design[train]).fit()
errors.append(Y[test][0] - fit.predict(design[test])[0])
return np.sqrt(np.mean(np.square(errors)))
linear = sm.add_constant(X)
logged = sm.add_constant(np.log(X))
print(f"linear in-sample R2 = {sm.OLS(Y, linear).fit().rsquared:.3f}"
f" LOOCV RMSE = {loocv_rmse(linear):.3f}")
print(f"log in-sample R2 = {sm.OLS(Y, logged).fit().rsquared:.3f}"
f" LOOCV RMSE = {loocv_rmse(logged):.3f}")linear in-sample R2 = 0.826 LOOCV RMSE = 1.283
log in-sample R2 = 0.891 LOOCV RMSE = 1.021
왜 하필 하나인가Why leave out exactly one
몇 개를 뺄지는 그 자체로 편향-분산 거래입니다.
How many observations to hold out is a bias-variance trade-off in its own right.
| LOOCV (k = N) | k-겹 (k = 5 또는 10) | |
|---|---|---|
| 훈련 크기 | 매번 N−1개 — 전체 적합과 거의 같음 | 80~90% |
| 편향 | 매우 낮음 | 약간 비관적 |
| 분산 | 높음 — 훈련 집합이 거의 겹쳐 오차가 상관됨 | 낮음 — 폴드가 덜 겹침 |
| 비용 | N번 적합 | k번 적합 |
| LOOCV (k = N) | k-fold (k = 5 or 10) | |
|---|---|---|
| Training size | N-1 each time, nearly the full-data model | 80-90% of the data |
| Bias | Very low | Slightly pessimistic |
| Variance | High: training sets overlap almost completely, so errors correlate | Lower: folds overlap less |
| Cost | N model fits | k fits |
실무 기본값은 5겹이나 10겹입니다. LOOCV는 N이 작아서 실제 덩어리를 뺄 여유가 없거나 모형에 닫힌 형태의 지름길이 있을 때 씁니다. OLS에는 그런 지름길이 있습니다. 햇 행렬의 대각 성분으로 잔차를 한 번의 적합에서 뽑아낼 수 있어서 LOOCV가 N번이 아니라 사실상 한 번의 회귀 비용입니다. 계량경제학에서 LOOCV가 살아남은 이유입니다.
The practical default is 5- or 10-fold. LOOCV is used when N is small enough that you cannot afford to hold out a real chunk, or when the model has a closed-form shortcut. OLS has one: leave-one-out residuals can be computed from a single fit using the hat matrix diagonal, so LOOCV costs essentially one regression rather than N. That is why it survives in econometrics despite being expensive in general.
교차검증이 낙관적으로 거짓말할 때When cross-validation lies, optimistically
평범한 k-겹은 관측치가 교환 가능하다고 가정합니다. 대개 아닙니다.
Plain k-fold assumes observations are exchangeable. They often are not.
- 사용자나 기업별 반복 관측 →
GroupKFold. 한 그룹의 모든 행이 같은 폴드로 가야 합니다. 아니면 모형이 훈련과 테스트에서 같은 사용자를 보고 점수가 부풀려집니다. - 시계열 →
TimeSeriesSplit. 과거로만 훈련합니다. 무작위 폴드는 모형이 미래에서 배우게 합니다. - 희귀 결과 →
StratifiedKFold. 폴드마다 클래스 비율을 유지합니다.
- Repeated observations per user or firm: use
GroupKFoldso all rows for a group land in the same fold. Otherwise the model sees the same user in training and test and the score is inflated. - Time series: use
TimeSeriesSplit, which only ever trains on the past. Random folds let the model learn from the future. - Rare outcome classes: use
StratifiedKFoldto keep the class balance stable across folds.
파이프라인 전체를 교차검증하십시오. 최종 추정량만이 아닙니다. 변수 선택·대체·스케일링은 모두 데이터에서 배웁니다. 전체 데이터로 변수를 고른 다음 모형만 교차검증하면 선택 단계가 이미 모든 폴드의 테스트 데이터를 봤습니다. 그렇게 나온 모형이 노트북에서는 분산의 60%를 설명하다가 운영에서는 아무것도 못 합니다.
Cross-validate the entire pipeline, not just the final estimator. Feature selection, imputation and scaling all learn from data. If you select features on the full dataset and then cross-validate the model, the selection step has already seen every fold test data. This is how you get a model that "explains 60% of variance" in the notebook and nothing at all in production.
튜닝할 때는 루프를 중첩하십시오. 하이퍼파라미터 선택과 성능 보고에 같은 데이터를 쓰면 보고된 숫자가 또 낙관적입니다. 안쪽 루프는 튜닝, 바깥 루프는 평가 — 정직한 추정치가 필요할 때의 올바른 구조입니다.
Nest the loops when tuning. Using cross-validation both to choose hyperparameters and to report performance reuses the same data for two purposes, and the reported number is again optimistic. An inner loop for tuning and an outer loop for evaluation is the correct construction when you need an honest estimate.
실무에서In practice
- LOOCV RMSE만이 기준은 아닙니다. 중첩된 모수적 설정 사이의 선택이라면 AIC·BIC가 더 싸고 선형모형에서 AIC는 LOOCV와 점근적으로 동등합니다. 교차검증은 모형이 중첩되지 않았거나 비모수적이거나 관심 손실함수가 로그우도가 아닐 때 값을 합니다.
- 예측 정확도는 식별이 아닙니다. 이 시리즈의 나머지가 여기 달려 있으니 강조해 둡니다. LOOCV는 어느 설정이 더 잘 예측하는지 알려 줍니다. 어느 쪽이 인과적으로 옳은지는 말해 주지 않습니다. 교란변수가 빠진 모형도 아름답게 예측하면서 개입 시 무슨 일이 생기는지는 틀린 답을 줄 수 있습니다.
- 모형 선택과 식별은 다른 문제이고 다른 도구로 풉니다. 이 시리즈의 인과추론 섹션이 두 번째 문제를 다룹니다.
- LOOCV RMSE is not the only criterion. For nested parametric specifications, AIC and BIC are cheaper, and for linear models AIC is asymptotically equivalent to LOOCV. Cross-validation earns its cost when models are non-nested, non-parametric, or the loss you care about is not log-likelihood.
- Prediction accuracy is not identification. This deserves emphasis because the rest of this series depends on it. LOOCV tells you which specification predicts better. It does not tell you which is causally correct. A model with an omitted confounder can predict beautifully and still give the wrong answer about what happens if you intervene.
- Model selection and identification are different problems solved with different tools. The causal inference section of this series is about the second one.
다음 편은 추정량 API 아래로 완전히 내려갑니다. fit을 호출하는 대신 OLS를 두 번 구현합니다. 닫힌 형태로 한 번, 확률적 경사하강으로 한 번. fit이 무슨 일을 하는지 알아 두면 그것이 언제 힘들어지는지 이해하는 데 쓸모가 있습니다.
The next post drops beneath the estimator API entirely: instead of calling fit, we implement OLS twice — once with the closed-form solution, once with stochastic gradient descent. Knowing what fit does turns out to matter for understanding when it struggles.