콘텐츠로 이동

데이터 누수 (Data Leakage)

핵심 요약: 데이터 누수는 모델이 시험 답을 미리 본 것과 같다. 학습 시 성능은 환상적이지만, 실전에서는 완전히 망한다. “성능이 너무 좋으면 일단 누수를 의심하라.”

  • 데이터 누수(Data Leakage): 학습 과정에서 실제 예측 시점에는 알 수 없는 정보가 유입되는 현상. 시험 전에 답안지를 본 것과 같다.
  • Train-Test Contamination: 테스트 데이터의 정보가 학습에 섞여 들어가는 유형. 전체 데이터에 스케일링을 먼저 적용하면 발생한다.
  • Target Leakage: 예측 시점에 사용할 수 없는 미래 정보가 특성에 포함된 유형. “퇴원일”로 사망 예측하는 것이 대표적.
  • Pipeline: 전처리와 모델을 하나로 묶어 누수를 자동 방지하는 도구. sklearn의 Pipeline이 대표적.

상황: 고객 이탈 예측 모델을 만든다고 하자.

단계누수 있음 (잘못된 방법)누수 없음 (올바른 방법)
1단계전체 데이터 스케일링데이터를 먼저 분할
2단계스케일링된 데이터 분할학습 데이터에만 스케일링 fit
3단계학습/평가테스트에는 transform만 적용
검증 정확도96%82%
실전 정확도73% (급락!)81% (안정)

누수가 있으면 검증 성능과 실전 성능의 괴리가 23%p나 발생한다. 올바른 방법은 검증과 실전이 거의 일치한다.

데이터 누수(Data Leakage)는 학습 과정에서 실제 예측 시점에는 사용할 수 없는 정보가 유입되는 현상이다. 데이터 누수가 있는 모델은 검증 시 뛰어난 성능을 보이지만, 실제 배포 후 성능이 급락한다. ML에서 가장 흔하면서도 발견하기 어려운 문제 중 하나이며, “too good to be true” 성능은 거의 항상 데이터 누수를 의심해야 한다.


데이터 누수라는 개념이 ML 커뮤니티에서 체계적으로 인식되기 시작한 것은 Kaggle 초기 대회들에서 반복적으로 발생한 누수 사건 덕분이다. 2011년 Heritage Health Prize 대회에서는 참가자들이 환자 ID를 통해 미래 시점의 정보를 간접적으로 유추할 수 있었고, 여러 대회에서 타겟과 직접 연결된 특성이 데이터에 포함되어 비현실적인 AUC 0.99 이상의 점수가 나오는 사례가 빈발했다.

이런 경험들이 축적되면서, Kaggle 커뮤니티는 “성능이 너무 좋으면 일단 누수를 의심하라”는 실무적 지혜를 형성했다. 이후 학계에서도 Kaufman et al. (2012)의 “Leakage in Data Mining” 논문이 데이터 누수를 공식적으로 분류하고 체계화했으며, 이는 오늘날 모든 ML 교육과정에서 다루는 필수 주제가 되었다.


Train-Test Contamination (학습-테스트 오염)

섹션 제목: “Train-Test Contamination (학습-테스트 오염)”

테스트 데이터의 정보가 학습 과정에 유입되는 경우이다.

대표적 사례:

  • 전체 데이터에 스케일링을 적용한 후 학습/테스트 분할
  • 교차 검증 바깥에서 전처리 (target encoding, SMOTE 등)
  • 동일 원본의 증강 데이터가 학습/테스트 세트에 분산

예측 시점에 사용할 수 없는 정보가 특성에 포함되는 경우이다.

예시:

  • 환자 퇴원일로 입원 중 사망 예측 (퇴원 = 생존 의미)
  • 주문 배송완료 여부로 주문 취소 예측
  • 고객의 해지 사유로 해지 예측

시계열 데이터에서 미래 데이터가 학습에 사용되는 경우이다.

원인: random split을 사용하면 미래 데이터가 학습 세트에 포함 해결: 반드시 time-based split 사용

타겟의 다른 표현이 특성으로 포함되는 경우이다.

예시: 타겟이 “매출”인데 “수익”이 특성에 포함 (매출 = 수익 + 비용)

신호설명
비정상적으로 높은 성능”too good to be true” — 현실적이지 않은 AUC > 0.99
의심스러운 특성 중요도한 특성이 압도적 중요도 → 타겟과 직접 관련 가능성
학습-테스트 성능 괴리 없음과적합이 전혀 없다면 누수 의심
배포 후 성능 급락개발 환경에서만 좋은 성능

Adversarial Validation:

학습/테스트 데이터를 구분하는 이진 분류기를 학습한다. AUC가 0.5보다 유의하게 높으면 두 데이터의 분포가 다르다는 신호이며, 누수 또는 분포 차이를 의미한다.

  • AUCadv0.5\text{AUC}_{\text{adv}} \approx 0.5: 학습/테스트 분포가 유사하다 (누수 없음)
  • AUCadv0.5\text{AUC}_{\text{adv}} \gg 0.5: 분포 차이가 존재한다 (누수 의심)

분포 차이 정량화 — PSI (Population Stability Index):

두 분포 간 차이를 정량적으로 측정하는 지표이다. 각 구간(bin)별 비율 차이를 합산한다.

PSI=i=1B(piqi)lnpiqi\text{PSI} = \sum_{i=1}^{B} (p_i - q_i) \cdot \ln\frac{p_i}{q_i}

여기서 pip_i는 기준 분포(reference)에서 구간 ii의 비율, qiq_i는 현재 분포에서 구간 ii의 비율이다.

PSI 범위해석
< 0.1유의한 변화 없음
0.1 – 0.25주의 필요
> 0.25유의한 분포 변화 (누수 또는 드리프트 의심)

KL 발산 (Kullback-Leibler Divergence):

학습 데이터와 서빙 데이터 간 분포 불일치를 측정하는 또 다른 방법이다.

DKL(PtrainPtest)=xPtrain(x)logPtrain(x)Ptest(x)D_{KL}(P_{\text{train}} \| P_{\text{test}}) = \sum_x P_{\text{train}}(x) \log \frac{P_{\text{train}}(x)}{P_{\text{test}}(x)}

DKL=0D_{KL} = 0이면 두 분포가 동일하며, 값이 클수록 분포 차이가 크다. KL 발산은 비대칭이므로 DKL(PQ)DKL(QP)D_{KL}(P \| Q) \neq D_{KL}(Q \| P)임에 유의한다.

3. 누수 예방 (Prevention) 다이어그램 파이프라인 사용:

# 잘못된 방법
scaler.fit(X) # 전체 데이터에 fit
X_scaled = scaler.transform(X)
X_train, X_test = split(X_scaled)
# 올바른 방법
X_train, X_test = split(X)
scaler.fit(X_train) # 학습 데이터에만 fit
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 가장 좋은 방법: Pipeline
from sklearn.pipeline import Pipeline
pipe = Pipeline([
('scaler', StandardScaler()),
('model', LogisticRegression())
])
pipe.fit(X_train, y_train) # 내부적으로 올바르게 처리

교차 검증에서의 올바른 전처리 수식:

잘못된 방법 — 전체 데이터에 전처리를 적용한 후 교차 검증을 수행하면 누수가 발생한다:

E^wrong=CV(transform(all data))leakage\hat{E}_{\text{wrong}} = \text{CV}(\text{transform}(\text{all data})) \quad \leftarrow \text{leakage}

올바른 방법 — 각 fold 내부에서 학습 데이터에만 fit한 전처리를 적용한다:

E^correct=1Kk=1KL(fk(transformk(Dval(k))))\hat{E}_{\text{correct}} = \frac{1}{K}\sum_{k=1}^{K} L\bigl(f_k(\text{transform}_k(D_{\text{val}}^{(k)}))\bigr)

여기서 transformk\text{transform}_kDtrain(k)D_{\text{train}}^{(k)}에만 fit된 변환이며, Dval(k)D_{\text{val}}^{(k)}kk번째 fold의 검증 데이터, KK는 fold 수이다.


점검 항목확인 방법
전처리가 학습 데이터에만 fit되었는가?코드 리뷰
시간 순서가 유지되었는가?학습/테스트의 시간 범위 확인
각 특성이 예측 시점에 사용 가능한가?도메인 전문가와 논의
동일 엔티티가 학습/테스트에 분산되지 않았는가?Group split 확인
Target encoding/SMOTE가 fold 내부에서 적용되었는가?파이프라인 검토
성능이 현실적인 수준인가?도메인 기대치 비교

시간 기반 분할의 중요성 다이어그램

Kaggle 대회에서 leakage 특성에 의존하여 높은 순위를 달성하는 경우가 있다. 그러나 이런 모델은 실제 환경에서는 작동하지 않는다. 대회 목적과 실제 배포 목적을 구분해야 한다.


데이터 누수 검사는 모든 ML 프로젝트에서 수행해야 한다. 특히:

상황누수 위험
시계열 데이터매우 높음 (temporal leakage)
그룹 데이터 (환자, 사용자)높음 (그룹 내 정보 공유)
외부 데이터 결합높음 (시점 불일치)
복잡한 전처리 파이프라인중간
성능이 비현실적으로 높을 때누수 확인 필수

주가 예측 모델: 백테스트 수익률 300%의 환상

섹션 제목: “주가 예측 모델: 백테스트 수익률 300%의 환상”

한 핀테크 스타트업이 딥러닝 기반 주가 예측 모델을 개발했다. 백테스트(backtesting) 결과 연간 수익률 300%라는 경이적인 성과를 보였고, 투자자들에게 자신 있게 프레젠테이션했다. 그러나 실제 트레이딩에 배포한 후 첫 달부터 손실이 발생했다. 문제의 원인은 다중 데이터 누수였다:

  • Temporal leakage: 학습/테스트 분할에 random split을 사용하여, 2023년 12월 데이터로 학습한 모델이 2023년 6월 주가를 “예측”하고 있었다
  • Feature leakage: 특성 중 하나인 “거래량 이동평균”이 미래 5일치 거래량을 포함한 윈도우로 계산되어 있었다
  • Look-ahead bias: 기업 실적 발표 데이터가 발표일이 아닌 분기 마지막 날 기준으로 조인되어, 아직 발표되지 않은 실적 정보가 특성에 포함되어 있었다

이 사례는 시계열 데이터에서 반드시 시간 기반 분할(time-based split)을 사용해야 하며, 모든 특성이 예측 시점에 실제로 사용 가능한 정보인지 꼼꼼히 검증해야 한다는 교훈을 남겼다.


  1. “스케일링은 누수가 아니다”: 전체 데이터의 평균/분산을 사용하면 테스트 데이터의 정보가 학습에 유입된다. 영향이 작을 수 있지만, 원칙적으로는 누수이다.

  2. “교차 검증이면 누수가 없다”: 교차 검증 바깥에서 전처리를 하면 여전히 누수이다. 모든 전처리는 각 fold 내부에서 수행해야 한다.

  3. “특성 중요도가 높으면 좋은 특성”: 특성 중요도가 비정상적으로 높으면 누수 특성일 가능성을 먼저 의심해야 한다.

  4. “데이터 누수는 큰 영향이 없다”: 사소해 보이는 누수도 모델의 실제 배포 성능을 크게 과대 추정하게 만들어, 잘못된 비즈니스 의사결정으로 이어질 수 있다.

  5. 이미지 증강 시 누수: 같은 원본 이미지의 증강 결과가 학습과 검증 세트에 동시에 포함되면, 모델이 증강 패턴을 학습하여 성능이 과대 추정된다.