CHAPTER 04 / SECTION 05
4.5 과거로 학습하고 미래로 평가하기
워크포워드 교차검증, 시간 경계의 누출, 보류 구간과 조합 평가를 다룹니다.
당시 몰랐던 값이 어느 단계로 들어왔는지 찾는다
지우가 월말 모델을 만들면서 다음 달 가격을 입력에 넣으면 주문 전에 알 수 없는 값으로 결정하게 된다. 이런 Look-ahead Bias(미래 정보 편향)는 가격 원본뿐 아니라 표준화나 거래 규칙에서도 생긴다. 오늘 남은 종목만 과거에도 쓴 경우, 나중에 고친 회계 수치를 공시 전 날짜에 붙인 경우도 당시 정보가 재현되지 않는다.
- Label Leakage(라벨 누출). 5거래일 뒤 수익률을 정답으로 만들었는데, 실수로 내일 수익률도 입력에 포함하면 미래의 일부를 미리 알려 준다. 정답 계산과 입력 계산에 쓰는 날짜를 각각 기록해 확인한다.
- Standardization Leakage(표준화 누출). 1~6월만 학습하더라도 1~12월의 평균과 표준편차로 입력을 변환하면 하반기의 분포가 이미 반영된다. 예를 들어 상반기 평균이 10이고 하반기 급등 때문에 전체 평균이 15라면, 상반기의 값 12가 평균 위에서 아래로 바뀐다. 각 학습 구간 안에서 평균과 표준편차를 구하고, 그 값으로 뒤의 검증 자료를 변환한다. 결측값 대체나 특징 선택도 같은 원칙을 따른다.
- Threshold Leakage(문턱값 누출). 최종 시험 기간에서 표준화 점수 2.0일 때 수익이 가장 높았다고 해서 그 값을 선택하면 시험 결과가 거래 규칙의 입력이 된다. 개발용 검증에서 문턱을 고정하고 이후 시험에서는 계산만 한다.
섞어서 나누는 대신 과거에서 미래로 이동한다
K-Fold Cross-Validation(K겹 교차검증)은 자료를 여러 묶음으로 나눈 뒤 한 묶음씩 검증에 쓰고 나머지로 학습하는 방법이다. 안정된 같은 분포에서 서로 독립적으로 얻은 관측이라면 순서를 섞어도 학습과 검증의 의미가 유지된다. 이를 Independent and Identically Distributed(독립 동일 분포, IID)라고 한다.
금융에서는 6월을 검증하면서 10월의 정답을 학습에 넣을 수 없다. 가까운 두 날짜가 같은 급락을 겪거나, 20일 수익률을 만들 때 같은 가격을 반복 사용하면 행끼리도 연결된다. 특정 자기회귀 모형에서 설명하고 남은 오차가 서로 무상관이면 일반 K겹이 예측 오차를 잘 추정할 수 있다는 결과도 있다. 모형이 구조를 놓쳐 오차에 패턴이 남거나 실전의 시점 제약을 재현해야 할 때는 그 예외에 기대지 않는다.
섞은 분할의 한 예
워크포워드 1차
워크포워드 2차
워크포워드 3차
왼쪽에서 오른쪽으로 시간이 흐른다. 섞은 분할은 검증 시점 뒤에도 학습이 있다. 아래 세 줄은 학습을 먼저 하고 한 달씩 전진한다. 날짜 내부의 경계 제외는 생략했다.
Walk-Forward Cross-Validation(워크포워드 교차검증)은 과거로 학습하고 미래를 평가하는 과정을 여러 번 반복한다.
- 과거 학습창과 그 뒤에 붙는 검증창을 정한다.
- 검증 첫 결정을 하기 전에 입력과 정답이 확정된 학습 행만 남긴다. 각 행의 특성도 그 행의 거래 시각에 만들 수 있었어야 한다.
- 남은 학습 자료로 전처리와 모델을 맞춘 뒤 미래 구간에 적용한다.
- 검증 구간의 정답이 나온 뒤 미리 정한 선택 지표를 계산한다.
- 정한 간격만큼 두 창을 전진시키고 다시 수행한다. 평균뿐 아니라 구간별 점수 차이도 본다.
Expanding Window(확장 학습창)는 시작일을 고정하고 확정된 자료를 계속 더한다. 추정이 덜 흔들릴 수 있지만 오래된 시장이 지금과 다르면 방해가 된다. Rolling Window(이동 학습창)는 최근 자료만 남긴다. 변화에 빨리 맞출 수 있지만 표본이 작아 추정이 크게 흔들릴 수 있다. 새 자료가 학습창의 약 1~5%에 이르거나 표본 외 성능이 지속해서 나빠질 때 다시 맞추는 것은 출발 기준이다. 10년 창에서는 월별 또는 분기별, 20거래일 창에서는 하루가 새 자료의 5%이므로 일별 갱신도 의미가 있다. 재학습 주기는 거래 주기와 별개로 기록한다.
입력과 정답이 참조하는 날짜까지 확인한다
5거래일 뒤 수익률을 맞히는 모델을 2월 10일 화요일 마감 뒤 학습한다고 가정한다. 휴장이 없다면 2월 3일 화요일에서 다섯 거래일 뒤가 2월 10일이다. 당일 종가가 학습 전에 도착했다면 2월 3일 행의 정답은 알 수 있지만, 2월 4일 행은 2월 11일까지 기다려야 한다. 검증이 2월 10일 장 시작 전에 시작된다면 그날 종가도 아직 쓸 수 없다.
2월 10일 마감 뒤에 만드는 학습 자료
2월 3일 라벨은 2월 10일 마감에 확정된다. 그 사이 네 날짜의 라벨은 더 늦게 확정되어 이번 학습에서 제외된다.
Label Buffer(라벨 버퍼)는 학습 행의 정답이 검증 구간과 겹치거나 검증 결정 때 아직 확정되지 않은 행을 빼는 장치다. 이런 겹치는 행 제거를 Purging(퍼징)이라고 한다. 예를 들어 검증 시작 15거래일 전의 20거래일 라벨은 경계 너머로 약 5일을 사용한다. 실제로는 예측 구간과 가격의 입수 시각을 맞춰 제외 범위를 계산한다. 하루 앞 라벨도 마지막 정답이 결정 전에 확정되고 겹침이 없을 때만 별도 공백이 필요 없다.
Feature Buffer(특성 버퍼)는 검증 뒤에도 학습 자료가 있는 분할에서 필요하다. 검증이 끝난 지 5거래일 뒤의 학습 행에 직전 20거래일 수익률을 넣으면 검증 기간의 가격을 다시 읽는다. 경계 뒤의 행을 일정 기간 비워 두는 Embargo(엠바고)를 적용해 겹침을 줄인다. 표본 길이의 1% 같은 경험칙보다 가장 긴 관측창과 실제 시간 의존을 먼저 본다. 검증 전 자료만 학습하는 기본 워크포워드에서는 검증 뒤 학습 행이 없으므로 이쪽 공백이 필요 없다.
버퍼는 달력일이 아니라 해당 시장의 거래일로 계산한다. 예를 들어 평일만 열린다고 가정하면 21일의 달력 기간에는 15거래일만 있다. 21거래일을 비워야 하는 곳에 달력 21일을 쓰면 필요한 거리에서 6거래일이 모자란다. 휴장일이 있으면 차이가 더 달라진다.
한 번 고정할 때와 계속 다시 고를 때
Sealed Holdout(봉인 보류 구간)은 특성, 모델, 주문 방식이나 보고 지표를 고르는 데 전혀 쓰지 않은 마지막 기간이다. 지우가 마지막 구간을 먼저 보고 손실이 작게 보이는 지표를 나중에 고르면 이미 봉인이 깨진 것이다.
- Fixed Holdout(고정 보류 평가). 개발 기간에 워크포워드로 후보 하나를 고른다. 비용, 한도, 점수를 주문으로 바꾸는 방법까지 고정한 뒤 보류 구간을 한 번 평가한다.
- Nested Walk-Forward(중첩 워크포워드). 실전에서 정기적으로 모델 설정을 다시 고른다면, 그 절차 자체를 먼저 고정한다. 각 바깥 시험 직전까지의 자료로만 안쪽 교차검증을 돌려 후보를 고른다. 허용된 과거로 다시 학습하고 다음 바깥 기간을 예측한다. 이전 시험 구간도 시간이 지나 정답이 확정되면 다음 시점에는 역사 자료가 될 수 있다. 단, 연구자가 시험 성과를 보고 재선택 규칙을 고쳐서는 안 된다.
3분기 시험 직전의 안쪽 분할 예
4분기 시험 직전의 안쪽 분할 예
안쪽 검증은 후보를 고르고 바깥 시험은 고르는 절차를 측정한다. 두 번째 줄을 최근 두 분기로만 학습·검증하면 고정 길이 이동창이 된다.
5년 과거창에 2년 시험 구간을 두면, 실전에서 여러 번 다시 조정할 절차를 한 번 고른 모델로 대신하기 어려울 수 있다. 중첩 방식은 선택 과정의 변동을 성과 추정에 반영하는 데 도움이 된다. 다만 후보와 특성이 많으면 계산량이 늘어난다. 날짜를 바꾸지 않고 계산을 나눠 실행하거나, 당시 이용할 수 있었던 특징을 저장해 다시 사용하고, 모형이 허용하면 새 자료만 반영할 수 있다.
역사 한 경로의 결과를 과신하지 않는다
우연히 평온한 해만 시험에 들어가면 위험한 전략도 좋아 보일 수 있다. Combinatorial Purged Cross-Validation(조합 퍼징 교차검증, CPCV)은 연속된 시간 블록을 만든 뒤 그중 여러 블록을 시험으로 뽑는 조합을 바꿔 결과의 분포를 본다. 네 블록에서 두 개를 고르면 순서를 구분하지 않으므로 네 개 중 하나, 남은 세 개 중 하나를 고른 12가지의 절반인 6가지다.
- Number of Splits(학습·시험 조합 수), 단위: 개
- Number of Blocks(전체 연속 시간 블록 수), 단위: 개
- Number of Test Blocks(조합마다 시험에 쓰는 블록 수), 단위: 개
시험 구간이 중간에도 오므로 라벨 겹침을 제거하고 시험 뒤 관측창을 막는 버퍼도 적용한다. 조합 분할이 시험 블록 뒤 자료를 학습에 쓰면, 버퍼를 적용해도 그 평가가 실전 시간 순서를 재현하지는 않는다. 따라서 경로에 따라 후보 평가가 얼마나 흔들리는지 진단하는 데 쓰고, 당시 사용 가능했던 과거만 쓰는 시험과 구분한다. 조합 수는 빠르게 커지며 자료가 짧거나 여러 블록이 비슷한 시장이면 결과가 많아도 독립적인 위기 사례가 늘어나지는 않는다.
평가 설계를 먼저 적고 자료 길이에 맞춘다
실험 전에 학습·검증·시험창 길이, 창 이동 간격, 재학습 주기, 라벨 구간, 가장 긴 특성 관측창, 최종 시험 날짜를 정한다. 같은 성과표에서 비교하려면 이 설계를 유지한다. 결과를 보고 분할을 바꿨다면 다른 평가 절차를 돌린 셈이므로 새 실행으로 표시한다. 예를 들어 setup.yaml에 기간을 기록하고 분할기가 그 설정을 읽도록 하면, 설명과 코드의 날짜가 어긋나는 일을 줄일 수 있다.
막대에서 미국 주식 패널은 나스닥100 장중 자료보다 평가에 쓸 연도가 훨씬 길다. 반대로 장중 자료는 짧은 기간에도 행이 많다. 연도 막대의 길이는 독립적인 정답 수나 전략 성과를 뜻하지 않는다. 서로 다른 시장 국면을 몇 번 경험했는지와 보류 기간에 판단할 기회가 얼마나 있는지를 따로 본 뒤 각 전략의 창 길이를 정한다.