Data Leakage
데이터 누수는 예측 시점에 알 수 없는 정보가 학습 또는 평가에 포함되어, 운영 환경에서는 재현되지 않는 높은 점수를 만들어 내는 현상입니다. 원인과 해결 방법을 다룹니다.
머신러닝(ML)의 데이터 누출은 모델의 학습 데이터 또는 평가에 실제 예측 시점에는 확보할 수 없는 정보가 포함될 때 발생합니다. 예를 들어 테스트 세트의 사례, 미래의 값 또는 정답을 인코딩하는 특성 등이 이에 해당합니다. 개발 및 모델 테스트 단계에서는 모델이 정확해 보이지만, 의존하던 지름길이 사라지므로 운영 환경에서는 성능이 떨어집니다. 데이터 누출은 재현 불가능한 결과의 주요 원인입니다. 머신러닝 기반 과학 연구 설문은 17개 분야에서 영향을 받은 논문 294편을 집계했으며, 내전 예측에서는 누출을 수정하자 복잡한 모델이 수십 년 된 로지스틱 회귀보다 우위에 있다는 보고가 사라졌습니다.
데이터 누출이 발생하는 방식#
데이터 분할, 처리 또는 입력 선택 과정에서 누출이 발생하며, 표 형식 모델, 시계열 분석, 동작 인식과 같은 비전 작업에서도 같은 실수가 반복됩니다.
- 학습-테스트 오염: 정규화 통계, 결측값 대체, 특성 선택처럼 데이터에서 학습하는 단계를 분할 전에 전체 데이터셋에 적용하면 학습 데이터에 평가 분할의 정보가 포함됩니다. 분할 전에 중복 이미지와 증강된 복사본을 만드는 경우도 같은 효과가 발생합니다.
- 그룹 누출: 연속된 비디오 프레임, 한 환자의 여러 스캔, 한 장면의 사진처럼 관련 샘플을 서로 다른 분할에 나눠 넣는 경우입니다. 그러면 모델이 작업 자체를 학습하는 대신 장면이나 인물을 인식해 높은 점수를 얻을 수 있습니다.
- 시간 누출: 시간 순서가 있는 데이터를 무작위로 분할하거나 예측 시점 이후의 값으로 특성을 계산하면 모델이 미래를 엿볼 수 있습니다.
- 타깃 누출: 입력이 레이블의 결과이거나 대리 변수인 경우입니다. 예를 들어 질병을 예측하는 모델에 "치료받음" 필드를 입력하는 경우입니다.
- 평가 데이터 재사용: 테스트 세트를 기준으로 튜닝하거나 벤치마크 질문이 대형 언어 모델의 웹 규모 사전 학습 데이터에 포함되면 평가 데이터가 학습 신호로 변합니다.
이미지에서도 타깃 누출이 발생할 수 있습니다. ChestX-ray14 데이터셋에서 기흉이 있는 테스트 세트 X선 이미지의 80%에 흉관도 나타났습니다. 흉관은 해당 질환 치료에 사용되는 튜브입니다. 이 데이터셋으로 학습한 분류기는 흉관이 있는 이미지에서 ROC AUC 0.94를 기록했지만, 감지기가 찾아내야 하는 미치료 사례인 흉관이 없는 이미지에서는 0.77에 그쳤습니다.
코드에서 데이터 누출 확인하기#
교차 검증 전에 데이터 의존적인 단계를 적합하는 것은 교과서적인 실수이며, 그 영향은 쉽게 측정할 수 있습니다. 다음 예시는 순수한 노이즈를 생성하므로 어떤 모델도 새 데이터에서 50% 이상의 정확도를 달성할 수 없습니다. 그런 다음 레이블을 가장 잘 구분하는 특성 20개를 선택하고, 로지스틱 회귀에 대해 두 번 교차 검증합니다. 한 번은 전체 샘플로 특성 선택을 적합하고, 다른 한 번은 각 학습 폴드에서 특성 선택을 다시 적합하는 scikit-learn 파이프라인 안에서 선택을 수행합니다.
import numpy as np
from sklearn.feature_selection import SelectKBest
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline
# Pure noise: 100 samples, 5,000 random features, random labels (true accuracy is 50%)
rng = np.random.default_rng(0)
X = rng.normal(size=(100, 5000))
y = rng.integers(0, 2, size=100)
# Leaky: pick the 20 features that best separate the labels using every sample, then cross-validate
X_selected = SelectKBest(k=20).fit_transform(X, y)
leaky = cross_val_score(LogisticRegression(), X_selected, y, cv=5).mean()
# Correct: feature selection is refit inside each training fold
pipeline = make_pipeline(SelectKBest(k=20), LogisticRegression())
clean = cross_val_score(pipeline, X, y, cv=5).mean()
print(f"Leaky CV accuracy: {leaky:.2f}, correct CV accuracy: {clean:.2f}")누출이 있는 방식은 무작위 레이블에서 85%의 정확도를 보고하지만, 파이프라인은 우연 수준인 48%를 보고합니다. 특성 5,000개와 샘플 100개가 있으면 일부 특성은 우연히 레이블과 상관관계를 보입니다. 검증 폴드를 포함해 특성을 선택하면 그 우연한 상관관계가 모든 폴드의 점수에 반영됩니다.
데이터 누출 방지#
방지는 데이터에서 학습하는 단계보다 먼저 수행하는 분할부터 시작해야 합니다. 그래야 검증 및 테스트 분할이 학습 과정에서 보이지 않습니다.
- 특성 엔지니어링 전에 분할하기: 스케일러, 결측값 대체기, 인코더, 특성 선택기는 학습 분할에만 적합하고, 다른 분할에는 변경 없이 적용합니다.
- 그룹 또는 시간 기준으로 분할하기: 한 환자, 비디오 또는 장면에 속한 모든 샘플을 하나의 분할에 포함하고, 과거 데이터로 학습해 미래 데이터를 테스트합니다.
- 해시 및 임베딩으로 중복 제거하기: 학습 전에 분할 간 파일 해시를 비교해 완전히 동일한 복사본을 찾고, 임베딩 유사도를 비교해 거의 중복된 항목을 찾습니다.
- 입력 감사하기: 각 특성을 예측 시점에 사용할 수 있는지 확인하고, 지배적인 특성 하나나 의심스러울 정도로 높은 점수가 발견되면 조사해야 할 버그로 취급합니다.
누출은 체크포인트 선택도 왜곡합니다. Ultralytics YOLO는 데이터셋 YAML에 나열된 train 이미지를 학습하고, 검증 적합도가 가장 높은 에포크의 best.pt을 저장합니다. 감지 작업에서 검증 적합도는 mAP50-95이므로 train와 val에 거의 중복된 프레임이 공유되면 체크포인트 선택 점수와 보고되는 점수가 모두 부풀려집니다.
데이터 누출과 관련 용어 비교#
- 과적합: 모델이 정상적인 학습 데이터의 노이즈를 암기해 깨끗한 검증 세트에서 낮은 점수를 얻습니다. 누출은 검증 점수 자체를 잘못되게 만들기 때문에 과적합된 모델이 좋아 보일 수 있습니다.
- 지름길 학습: 모델이 레이블과 상관관계가 있는 워터마크나 배경 같은 우연한 단서에 의존합니다. 배포 환경에서 사용할 수 없는 정보가 학습 또는 평가 과정에 단서로 유입되는 경우가 누출입니다.
- 데이터 보안: 사이버 보안에서 데이터 누출은 민감한 데이터가 권한이 없는 사람에게 노출되는 것을 의미하며, 접근 제어, 암호화, 데이터 손실 방지 도구로 대응합니다. 두 용어는 이름만 같습니다.










