흔한 실수 (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 |
잘못된 교차 검증 — 전체 데이터에서 전처리 후 교차 검증을 수행하면 검증 오차가 과소 추정된다:
올바른 교차 검증 — 각 fold 내부에서 전처리를 수행해야 한다:
여기서 전처리의 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\)번의 튜닝 시도를 하면, 검증 세트에서의 최적 성능은 실제보다 낙관적으로 추정된다:
- \(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)는 두 분포 간의 안정성을 측정한다:
- \(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 프로젝트에서 참고해야 한다. 특히:
- 새로운 프로젝트를 시작할 때
- 모델 성능이 비현실적으로 높을 때
- 프로덕션 배포 전 최종 검증 시
- 코드 리뷰 시
- 팀에 새로운 멤버가 합류할 때
흔한 오해와 함정¶
-
"나는 경험이 많으니 이런 실수를 하지 않는다": 압박과 시간 제약 하에서 누구나 실수할 수 있다. 체크리스트와 자동화된 파이프라인으로 방지하라.
-
"한 번 확인했으니 됐다": 코드 변경, 데이터 업데이트 시 새로운 누수가 발생할 수 있다. CI/CD에 검증을 통합하라.
-
"Kaggle 대회와 실무는 같다": 대회에서는 누수 특성도 활용하지만, 실무에서는 배포 시점의 특성 사용 가능성을 반드시 확인해야 한다.
-
"검증 성능이 좋으니 배포해도 된다": 프로덕션에서는 데이터 drift, 지연시간, 공정성 등 검증 성능 이외의 요소도 중요하다.
다른 주제와의 연결¶
- 데이터 누수: 가장 흔한 실수의 상세 설명
- 불균형 데이터: 지표 선택의 중요성
- ML 파이프라인 설계: 올바른 파이프라인으로 실수 방지
- 실험 추적: 재현 가능한 실험
- 모델 배포: Training-Serving Skew
- 윤리적 AI: 공정성 관련 실수
- ML 시스템 설계 패턴: 프로덕션 운영의 실수