This repository was archived by the owner on Sep 24, 2026. It is now read-only.
[검증] 백테스트를 표본 외로 돌린다 — v3 는 살아남았고, 재현율은 떨어졌다 - #96
Merged
Merged
Conversation
⚠️ `LIST_EDATE` 가 **'20260714' 로 하드코딩**돼 있었다. 그래서 두 달 뒤에 다시 돌려도 같은 68주를 다시 읽었다 — **다시 돌린다고 새로 아는 것이 없었다.** 이게 특히 나쁜 자리인 이유 — 배포된 점수표(v3)는 **바로 그 68주에서 후보 10개를 비교해 고른 것**이다. 고른 데이터로 다시 재면 잘 나오는 게 당연하고, 고밀도 주가 26건뿐이라 과적합 위험이 실질적이었다. 그걸 확인할 유일한 방법이 **선택에 쓰이지 않은 새 주간**인데, 종료일이 고정돼 있으면 그 데이터가 영영 들어오지 않는다. 기본을 실행일로 두고 BACKTEST_FROM / BACKTEST_TO 로 덮을 수 있게 했다. 특정 시점을 재현해야 할 때는 BACKTEST_TO 로 고정한다. 고친 뒤 표본이 136 → 156 단위(고밀도 26 → 34)로 늘었다.
과제 A·B 의 "룰" 숫자는 `DEFAULT_RULE_SCORES` 로 낸 것인데, 그건 **v1 폴백**이다 (risk-factors.ts 주석: "이건 DB 에 룰이 없을 때의 안전망이지 운영 점수표가 아니다"). 실제 운영 점수는 RISK_RULE_VERSION 이 고른 DB 값(v3)에서 온다. 그래서 헤드라인만 읽으면 **AUC 0.742 를 현행 성적으로 오해한다.** 배포본(v3)은 같은 실행에서 AUC 0.871 이고, 그 숫자는 과제 E 표 안에만 있었다.⚠️ 홀드아웃 경고 문구도 '표본 20개(고밀도 3개)' 로 하드코딩돼 있었다. 데이터가 늘어 실제로는 40개(고밀도 11개)가 됐는데도 "순위를 논할 수준이 아니다" 라고 말했다. **주의 문구가 실제보다 세면 맞는 결과까지 버리게 된다.** 실제 수를 세어 찍고, 고밀도가 15건 미만일 때만 강한 경고를 낸다.
선택 당시(136) 표본외 포함(156) 2026 홀드아웃(40) v3 AUC 0.886 0.871 0.842 베이스라인 AUC 0.823 0.812 0.809 v3 재현율 73.1% 64.7% 63.6% **① 순위 능력은 유지됐다.** 베이스라인과의 격차가 +0.063 → +0.059 로 거의 그대로이고, 홀드아웃에서도 앞선다. 과적합으로 무너지지 않았다. **② 재현율은 떨어졌다.** 73.1% → 64.7%. 같은 기간 베이스라인은 69.2% → 73.5% 로 올랐다. 즉 지금은 **"지난주 NIFS 보고서를 그대로 베끼는 것" 이 엔진보다 더 많이 잡는다.** 안전 서비스에서 미경보는 가장 피해야 할 결과이므로 가볍게 볼 수 없다.⚠️ 다만 34건 중 22 vs 25, **3주 차이**다. 짝지은 부트스트랩에서 v3 와 구별되는 후보가 하나도 없었다(ΔAUC CI 가 전부 0 을 포함). **지금 데이터로 점수표를 다시 고르면 그건 또 한 번의 선택-위-검증이다.** 이번에는 고치지 않는다 — 그게 이번 실행의 결론이다. 다음 재실행에서 재현율 격차가 유지되면, 그때는 (b3) 고40/저10 을 놓고 **미경보와 과경보 중 무엇을 감수할지** 정해야 한다. 그건 측정이 아니라 정책 결정이다.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #95
발견
두 달 뒤에 다시 돌려도 같은 68주를 다시 읽었다. 배포된 v3 는 바로 그 68주에서 후보 10개를 비교해 고른 것이라, 같은 데이터에서 잘 나오는 것은 당연하다. 고밀도 주가 26건뿐이니 과적합 위험이 실질적이었고, 확인할 유일한 방법인 새 주간이 영영 들어오지 않고 있었다.
고치니 표본이 136 → 156 단위(고밀도 26 → 34)로 늘었다.
결과 — v3 는 살아남았다
① 순위 능력은 유지됐다. 베이스라인과의 AUC 격차가 +0.063 → +0.059 로 거의 그대로이고, 2026 홀드아웃에서도 앞선다. 과적합으로 무너지지 않았다.
② 재현율은 떨어졌다. 73.1% → 64.7%. 같은 기간 베이스라인은 69.2% → 73.5% 로 올랐다. 지금은 "지난주 NIFS 보고서를 그대로 베끼는 것" 이 엔진보다 더 많이 잡는다. 안전 서비스에서 미경보는 가장 피해야 할 결과다.
그래서 이번에는 점수표를 고치지 않는다. 지금 데이터로 다시 고르면 그건 또 한 번의 선택-위-검증이고, 이 PR 이 막으려는 것이 정확히 그것이다.
함께 고친 보고 문제 둘
① 헤드라인이 배포본이 아니었다. 과제 A·B 의 "룰" 은
DEFAULT_RULE_SCORES(v1 폴백)다 — 코드 주석에도 "운영 점수표가 아니다" 라고 적혀 있다. 헤드라인만 읽으면 AUC 0.742 를 현행 성적으로 오해한다(v3 는 같은 실행에서 0.871). 두 절에 무엇으로 낸 숫자인지 적었다.② 홀드아웃 경고가 하드코딩이었다.
'표본 20개(고밀도 3개)'가 박혀 있어, 실제로 40개(고밀도 11개)가 된 뒤에도 "순위를 논할 수준이 아니다" 라고 말했다. 주의 문구가 실제보다 세면 맞는 결과까지 버리게 된다. 실제 수를 세고, 고밀도 15건 미만일 때만 강한 경고를 낸다.다음 재실행에서 볼 것
재현율 격차가 유지되는가. 유지되면 그때는 (b3) 고40/저10(재현율 CI 최대 +14.8%, 오경보율 최대 +8.8%)을 놓고 미경보와 과경보 중 무엇을 감수할지 정해야 한다. 그건 측정이 아니라 정책 결정이다.
검증
과제 E-5(시간 분할 홀드아웃)는 이미 구현돼 있었다 — 데이터가 안 늘어서 쓸모가 없었을 뿐이다.