콘텐츠로 이동

흔한 실수 (Common Mistakes in ML)

개요

ML 프로젝트에서 반복적으로 발생하는 실수들이 있다. 이 실수들은 대부분 성능의 과대 추정, 잘못된 결론, 또는 프로덕션에서의 실패로 이어진다. 경험이 풍부한 실무자도 실수할 수 있으며, 이를 미리 인지하고 체계적으로 방지하는 것이 중요하다.


핵심 개념

1. 데이터 몰래 보기 (Data Snooping)

테스트 데이터로 모델을 선택하거나 튜닝하여, 성능이 과도하게 낙관적으로 추정되는 문제이다.

잘못된 방법 올바른 방법
테스트 세트 결과를 보고 모델 수정 Hold-out 테스트 세트는 최종 1회만 사용
여러 모델을 테스트 세트로 비교 검증 세트로 비교, 테스트 세트는 최종 모델에만

2. 부적절한 검증 (Improper Validation)

실수 올바른 방법
시계열에 random split Time-based split
그룹 데이터에서 그룹을 분할하지 않음 Group K-Fold
교차 검증 전에 전처리 각 fold 내부에서 전처리
Stratification 없이 불균형 데이터 분할 Stratified K-Fold

잘못된 교차 검증 — 전체 데이터에서 전처리 후 교차 검증을 수행하면 검증 오차가 과소 추정된다:

\[\hat{E}_{\text{wrong}} = \frac{1}{K}\sum_{k=1}^{K} L\bigl(f^{(-k)},\; \tilde{D}_k\bigr), \quad \tilde{D} = \text{preprocess}(D) \quad \text{(누수!)}\]

올바른 교차 검증 — 각 fold 내부에서 전처리를 수행해야 한다:

\[\hat{E}_{\text{correct}} = \frac{1}{K}\sum_{k=1}^{K} L\bigl(f^{(-k)}_{\text{pipe}},\; D_k\bigr), \quad f^{(-k)}_{\text{pipe}} = \text{preprocess}_{D \setminus D_k} \circ \text{model}_{D \setminus D_k}\]

여기서 전처리의 fit은 \(D \setminus D_k\)(학습 fold)에서만 수행하고, \(D_k\)(검증 fold)에는 transform만 적용한다.

3. 클래스 불균형 무시

정확도(accuracy)만 보고 "모델이 잘 작동한다"고 판단하는 실수.

Before: "Accuracy 98%로 우수한 모델!"
After: "소수 클래스 Recall 0%... 모델이 다수 클래스만 예측"

불균형 데이터에서는 F1, AUROC, AUPRC를 사용해야 한다.

4. 잘못된 지표 선택

비즈니스 목표와 최적화 지표의 불일치.

상황 잘못된 지표 적절한 지표
스팸 필터 Recall (정상 메일 차단 위험) Precision 우선
질병 선별 검사 Precision (환자 누락 위험) Recall 우선
추천 시스템 Accuracy nDCG, MAP
회귀 (이상치 있음) MSE MAE 또는 Huber

5. 검증 세트 과적합 (Overfitting to Validation Set)

반복적인 하이퍼파라미터 튜닝으로 validation set에 과적합되는 문제. \(n\)번의 튜닝 시도를 하면, 검증 세트에서의 최적 성능은 실제보다 낙관적으로 추정된다:

\[E_{\text{true}} \leq \hat{E}_{\text{val,best}} + \sqrt{\frac{\ln n}{2 |D_{\text{val}}|}}\]
  • \(n\): 하이퍼파라미터 조합의 시도 횟수
  • \(|D_{\text{val}}|\): 검증 세트 크기
  • \(\hat{E}_{\text{val,best}}\): 검증 세트에서 가장 좋았던 성능

이 부등식(union bound + Hoeffding)은 시도 횟수 \(n\)이 증가할수록 과적합 위험이 \(\sqrt{\ln n}\)으로 커짐을 보여준다.

해결: - Nested cross-validation - 별도의 최종 test set 유지 - 튜닝 횟수를 제한하고 기록

6. Baseline 미설정

복잡한 모델부터 시작하면 개선 여부를 판단할 수 없다.

규칙: 항상 가장 간단한 모델로 baseline을 설정한 후, 복잡성을 늘려라.

7. 분할 후 특성 공학

실수 결과
전체 데이터에서 target encoding 데이터 누수
전체 데이터에서 feature selection 테스트 정보 유입
전체 데이터에서 스케일링 fit 미미하지만 원칙적 누수

올바른 순서: 분할 → 학습 데이터로만 전처리 fit → 테스트에 transform

8. Training-Serving Skew

학습 시와 배포 시의 데이터 전처리 불일치. 누수 탐지를 위해 학습 세트와 테스트 세트의 특성 분포 차이를 정량적으로 측정할 수 있다. PSI (Population Stability Index)는 두 분포 간의 안정성을 측정한다:

\[\text{PSI} = \sum_{i=1}^{B}\bigl(p_i^{\text{actual}} - p_i^{\text{expected}}\bigr) \ln\frac{p_i^{\text{actual}}}{p_i^{\text{expected}}}\]
  • \(B\): 구간(bin)의 수
  • \(p_i^{\text{actual}}\): 실제(서빙) 데이터에서 \(i\)번째 구간의 비율
  • \(p_i^{\text{expected}}\): 학습 데이터에서 \(i\)번째 구간의 비율
  • \(\text{PSI} < 0.1\): 안정, \(0.1 \leq \text{PSI} < 0.25\): 주의, \(\text{PSI} \geq 0.25\): 분포 변화 심각

원인: 학습은 Python/pandas, 서빙은 Java/C++ 등 다른 환경에서 전처리

해결: 전처리 파이프라인을 모델과 함께 직렬화 (sklearn Pipeline, ONNX 등)


상세 내용

실수 방지 체크리스트

flowchart TD
    A["ML 프로젝트 체크리스트"] --> B["✅ Baseline 설정했는가?"]
    B --> C["✅ 데이터 분할이 적절한가?<br>(시간순, 그룹, 층화)"]
    C --> D["✅ 전처리가 fold 내부에서<br>수행되는가?"]
    D --> E["✅ 평가 지표가 비즈니스<br>목표와 일치하는가?"]
    E --> F["✅ 데이터 누수가 없는가?"]
    F --> G["✅ 테스트 세트를<br>최종 1회만 사용했는가?"]
    G --> H["✅ 오류 분석을 했는가?"]
    H --> I["✅ 학습-서빙 일관성을<br>확인했는가?"]

Before/After 비교

실수 Before (잘못된 방법) After (올바른 방법)
전처리 순서 scale(전체) → split → train split → scale.fit(train) → transform
시계열 분할 random_split(data) data[:cutoff], data[cutoff:]
SMOTE 시점 SMOTE(전체) → cross_val for fold: SMOTE(train_fold)
성능 평가 accuracy = 99% → 배포 AUPRC, F1 확인 → 오류 분석 → 배포
Baseline 바로 딥러닝 시작 로지스틱 회귀 → XGBoost → 딥러닝

언제 사용하는가

이 체크리스트는 모든 ML 프로젝트에서 참고해야 한다. 특히:

  • 새로운 프로젝트를 시작할 때
  • 모델 성능이 비현실적으로 높을 때
  • 프로덕션 배포 전 최종 검증 시
  • 코드 리뷰 시
  • 팀에 새로운 멤버가 합류할 때

흔한 오해와 함정

  1. "나는 경험이 많으니 이런 실수를 하지 않는다": 압박과 시간 제약 하에서 누구나 실수할 수 있다. 체크리스트와 자동화된 파이프라인으로 방지하라.

  2. "한 번 확인했으니 됐다": 코드 변경, 데이터 업데이트 시 새로운 누수가 발생할 수 있다. CI/CD에 검증을 통합하라.

  3. "Kaggle 대회와 실무는 같다": 대회에서는 누수 특성도 활용하지만, 실무에서는 배포 시점의 특성 사용 가능성을 반드시 확인해야 한다.

  4. "검증 성능이 좋으니 배포해도 된다": 프로덕션에서는 데이터 drift, 지연시간, 공정성 등 검증 성능 이외의 요소도 중요하다.


다른 주제와의 연결