from sklearn.model_selection import train_test_splitfrom sklearn.preprocessing import StandardScalerfrom sklearn.decomposition import PCAfrom imblearn.over_sampling import SMOTEfrom imblearn.pipeline import Pipeline# 1) 분할 먼저 — 모든 fit은 학습셋에서만 (누수 방지)X_tr, X_te, y_tr, y_te = train_test_split( X, y, test_size=0.2, stratify=y, random_state=42)# 2) 분포·상관·불균형을 시각화 (학습셋 기준)# 히스토그램/박스플롯, 상관 히트맵, 클래스 분포 막대# 3) 표준화 → 차원 축소 (또는 특성 선택)# 4) 리샘플링은 학습셋에서만, Pipeline 안에서pipe = Pipeline([ ("scaler", StandardScaler()), ("pca", PCA(n_components=0.95)), ("smote", SMOTE(random_state=42)),])X_tr_proc, y_tr_proc = pipe.fit_resample(X_tr, y_tr)
[원시 데이터]
│
① 분할 (stratify=y) ────────────────→ [테스트셋] 봉인
│ │
② 시각화 (Day 3) │
├ 분포 → 치우침·이상치 │
├ 상관 히트맵 → 다중공선성 후보 │
└ 클래스 막대 → 불균형 확인 │
│ │
③ 표준화 (fit: 학습셋) │
│ │
④ 차원 처리 │
├ 해석 필요 → 특성 선택 (Day 2) │
└ 해석 불필요 → PCA (Day 1) │
│ │
⑤ 불균형 대응 (Day 4) │
├ 리샘플링 → fold의 학습 부분에서만 │
└ 또는 클래스 가중치 (데이터 불변) │
│ │
⑥ 학습 → 검증셋에서 임계값 결정 │
│ │
⑦ 최종 평가 ←──── ③·④에서 학습한 변환을 transform만 적용
(PR-AUC / F1 — 정확도 아님)
이 워크플로를 묶는 원칙은 "분할 먼저, 학습셋에서만 fit"이다. 표준화·PCA·SMOTE·특성 선택·결측 대치 — 데이터에 의존하는 모든 변환은 학습셋에서 통계/규칙을 배우고 테스트에는 적용만 해야 한다. 이 한 원칙이 Week 3(정제·인코딩)부터 Week 4(차원·불균형)까지를 관통한다.
차원이 너무 많다 / 성능이 안 나온다
│
├─ 변수 단위 설명이 필요한가?
│ 예 → 특성 선택 (필터 → 임베디드 → RFE 순으로 좁힌다)
│ 아니오 ↓
├─ 목적이 "군집이 있는지 눈으로 보기"인가?
│ 예 → t-SNE (시각화까지만. 모델 입력 금지)
│ 아니오 ↓
├─ 메모리를 넘는 규모인가?
│ 예 → SageMaker 내장 PCA (특성 많으면 randomized)
│ 아니오 → scikit-learn PCA (표준화 후 n_components=0.95)
│
타깃이 심하게 치우쳐 있다
│
├─ 데이터를 바꿔도 되는가?
│ 아니오 → 클래스 가중치 / 임계값 이동
│ 예 ↓
├─ 데이터가 매우 큰가?
│ 예 → 무작위 언더샘플링(속도 확보)
│ 아니오 → SMOTE (fold 내부에서만)
│
└─ 평가는 무조건 PR-AUC · F1 · 재현율 (정확도 금지)
헷갈리기 쉬운 세 함정. (1) "t-SNE 임베딩을 분류기 입력으로 쓴다" → 틀림(시각화 전용). (2) "불균형 데이터에서 정확도 99%면 좋다" → 정확도 역설. (3) "분할 전에 SMOTE·스케일링을 적용한다" → 데이터 누수. 이 셋만 확실히 잡아도 EDA 영역 점수가 안정된다.
불균형 대응과 지표 선택을 따로 묻는 것처럼 보여도 한 세트로 답해야 하는 지문이 많다. "SMOTE를 적용했다"까지만 고르고 평가를 정확도로 둔 보기는 오답이다. 리샘플링·가중치·임계값 중 무엇을 쓰든 평가는 PR-AUC·F1·재현율로 간다.