피처 전처리¶
6.1 전통 스코어카드 vs 트리 모형의 변수 처리¶
전통 스코어카드에서는 모형에 변수를 넣기까지 상당한 전처리가 필요했다.
Fine Classing → Coarse Classing → WoE 변환 → IV 기반 선별 → 모형 투입
이 과정이 필요한 이유는 로지스틱 회귀가 선형 결합만 학습할 수 있기 때문이다. WoE 변환은 비선형 패턴을 사전에 선형화하는 작업이고, 구간화는 그 전제 조건이다.
트리 기반 모형에서는 이 전처리 흐름이 구조적으로 불필요하다.
| 전처리 단계 | 전통 스코어카드 | 트리 앙상블 | 이유 |
|---|---|---|---|
| 구간화 (Classing) | 필수 (Fine → Coarse) | 불필요 | 트리 split이 최적 분할점을 자동 탐색 |
| WoE 변환 | 필수 | 불필요 | 트리는 비선형 관계를 직접 학습 |
| 정규화/표준화 | 불필요 (WoE가 스케일 통일) | 불필요 | 트리는 크고 작음만 판단 — 단조변환은 split 결과를 바꾸지 않음 |
| 결측치 처리 | 별도 구간화 필요 | XGB/LGBM은 자동 처리 | 결측치를 좌/우 어디로 보낼지 학습으로 결정 |
| 이상치 처리 | 구간 경계 조정 | 대부분 자동 분리 | 트리 split이 이상치를 별도 리프로 분리 |
불필요 ≠ 안 해도 된다
위 표는 "트리가 구조적으로 처리할 수 있다"는 뜻이지, "전처리를 전혀 안 해도 최적 성능이 나온다"는 뜻이 아니다. 데이터 품질이 심각하게 나쁘거나, 변수 수가 극도로 많거나, 도메인 지식이 반영되어야 하는 경우에는 트리 모형에서도 전처리가 성능을 개선한다.
6.2 스케일링이 불필요한 이유¶
트리 모형에서 가장 흔한 오해 중 하나가 "변수를 정규화해야 하는 것 아닌가?"이다.
트리의 분할은 "변수 X의 값이 임계점 t보다 큰가 작은가"만 판단한다. 이 판단은 변수의 순서(rank)에만 의존하고, 절대적 크기에는 무관하다. 따라서:
- 표준화 (StandardScaler: 평균 0, 분산 1로 변환) → 순서 불변 → 트리에 영향 없음
- 정규화 (MinMaxScaler: 0~1로 변환) → 순서 불변 → 트리에 영향 없음
- 로그 변환 → 순서 불변 → 트리에 영향 없음
이것은 로지스틱 회귀와의 근본적 차이다. 로지스틱 회귀는 각 변수의 계수(β)가 변수의 스케일에 직접 영향받으므로, WoE 변환(또는 표준화)이 필수적이다. 트리는 분기의 의미가 대소 비교이므로 스케일과 무관하다.
예외: float32 정밀도 문제
sklearn과 일부 프레임워크의 트리 구현체는 내부적으로 float32로 연산한다. float32의 유효숫자는 약 7자리이므로, 극단적으로 큰 값(예: 999,999,990 vs 999,999,999)에서는 끝자리 차이를 구분하지 못한다.
이런 경우에는 스케일링이 아니라 binning이나 capping이 해법이다. "스케일링 불필요"라는 원칙의 예외는 스케일 자체가 아니라, 구현체의 수치 정밀도 한계에서 발생한다.
6.3 범주형 변수 인코딩¶
로지스틱 회귀에서는 범주형 변수를 WoE로 변환하여 연속형처럼 투입했다. 트리 모형에서는 WoE 변환 없이 범주형 변수를 직접 다루는 방법이 여러 가지 있다.
Label Encoding¶
각 범주에 정수를 부여한다. 예를 들어 직업군이 {회사원, 자영업, 공무원, 전문직}이면 {0, 1, 2, 3}으로 변환한다.
| 장점 | 단점 |
|---|---|
| 구현이 가장 단순 | 범주 간 순서 관계가 없는데 순서가 부여됨 |
| 메모리 효율적 | 트리가 "회사원(0) < 자영업(1)" 같은 무의미한 대소 비교를 수행 |
| XGBoost/LightGBM에서 실무적으로 잘 작동 | 범주 수가 많으면 split 효율이 떨어질 수 있음 |
트리에서 Label Encoding이 작동하는 이유
범주 간 순서에 의미가 없더라도, 트리는 모든 가능한 분할점을 탐색하므로 결국 유의미한 범주 조합을 찾아낸다. 예를 들어 {회사원, 공무원} vs {자영업, 전문직}이 최적 분할이라면, Label Encoding 상에서 {0, 2} vs {1, 3}으로 나누는 split이 발견된다. 단, 이 과정이 비효율적일 수 있어 범주 수가 매우 많으면(수백 개 이상) 다른 방법을 검토한다.
Target Encoding¶
각 범주를 해당 범주의 타겟 평균값으로 대체한다. 예를 들어 지역별 평균 Bad Rate(서울: 0.03, 경기: 0.05, 부산: 0.07 등)로 변환한다.
| 장점 | 단점 |
|---|---|
| 범주의 순서가 타겟과의 관계를 반영 | Data Leakage 위험 — 타겟 정보가 피처에 유입 |
| 높은 카디널리티(범주 수)에도 대응 가능 | 소수 샘플 범주에서 과적합 |
| 트리 split이 효율적 (의미 있는 순서) | 정교한 CV 기반 인코딩 필요 |
Data Leakage 방지
Naive하게 전체 데이터의 타겟 평균을 사용하면, 학습 데이터의 타겟 정보가 피처에 직접 새어들어간다. 이를 방지하기 위해:
- K-Fold 기반 인코딩: 각 Fold에서 자신이 속하지 않은 데이터의 타겟 평균을 사용
- Smoothing: 글로벌 평균과 범주별 평균의 가중 평균 → 소수 샘플 범주의 극단값 방지
One-Hot Encoding¶
각 범주를 별도의 이진(0/1) 컬럼으로 확장한다. 직업군 4개 → job_회사원, job_자영업, job_공무원, job_전문직 4개 컬럼이 생성된다.
| 장점 | 단점 |
|---|---|
| 범주 간 순서를 부여하지 않음 | 카디널리티가 높으면 컬럼 수 폭증 |
| 해석이 직관적 | 트리 모형에서 split 효율이 떨어짐 |
| 모든 알고리즘에서 사용 가능 | 희소(sparse) 행렬 생성 → 메모리 비효율 |
트리 모형에서 One-Hot의 한계
One-Hot Encoding은 트리 모형에서 비효율적이다. 범주가 K개이면 K개의 이진 변수가 생성되고, 트리는 이들을 독립 변수로 취급한다. {회사원, 공무원} vs 나머지 같은 분할을 하려면 여러 번의 split이 필요한데, Label Encoding이라면 한 번의 split으로 가능하다.
특히 Boosting에서 max_depth가 얕을 때(depth=3~5), 제한된 split 횟수를 One-Hot 변수가 소비하면 다른 변수의 정보를 학습할 기회가 줄어든다.
LightGBM의 Native Categorical¶
LightGBM은 범주형 변수를 인코딩 없이 직접 처리하는 기능을 제공한다. 범주형 변수를 category 타입으로 지정하고 categorical_feature 파라미터로 전달하면 된다.
LightGBM은 내부적으로 범주를 최적의 두 그룹으로 분할하는 알고리즘을 사용한다. Label Encoding의 인위적 순서 문제와 One-Hot의 비효율성을 모두 회피한다.
인코딩 선택 가이드¶
| 상황 | 권장 인코딩 |
|---|---|
| 범주 수 ≤ 10, XGBoost | Label Encoding — 단순하고 실무적으로 충분 |
| 범주 수 ≤ 10, LightGBM | Native Categorical — 별도 인코딩 불필요 |
| 범주 수 > 50 | Target Encoding (CV 기반) — 차원 폭증 방지 |
| 로지스틱 회귀 / 신경망 | One-Hot 또는 Target Encoding |
| 순서가 명확한 범주 (학력, 등급 등) | Ordinal Encoding — 의미 있는 순서 그대로 사용 |
6.4 결측치 처리¶
신용평가 데이터에서 결측은 흔하다. "CB 미조회", "거래 이력 없음", "소득 미신고" 등 — 그리고 이 결측 자체가 중요한 신호인 경우가 많다.
XGBoost/LightGBM의 자체 결측 처리¶
XGBoost와 LightGBM은 결측치(NaN)를 별도 전처리 없이 학습할 수 있다. 원리는 다음과 같다:
트리가 분할할 때, 결측치를 가진 샘플을 왼쪽으로 보낼지 오른쪽으로 보낼지를 학습으로 결정한다. 구체적으로:
- Split 후보 (변수, 임계점)를 정한다
- 결측 샘플을 왼쪽에 넣고 loss를 계산한다
- 결측 샘플을 오른쪽에 넣고 loss를 계산한다
- loss가 더 작은 방향을 default direction으로 채택한다
[DTI > 40%?]
/ | \
≤40% NaN→? >40%
↙ ↘
왼쪽 시도 오른쪽 시도
loss=0.32 loss=0.28 ← 오른쪽 채택
이 방식의 장점은 결측 자체가 정보가 된다는 것이다. "소득을 신고하지 않은 사람"과 "소득이 낮은 사람"이 유사한 리스크를 가진다면, 모형이 이를 자동으로 학습한다.
Imputation을 먼저 하면 정보를 잃을 수 있다
XGBoost/LightGBM을 사용할 때, 결측치를 평균이나 중앙값으로 채운 후 모형에 넣으면 "결측이었다"는 정보가 사라진다. 결측 패턴이 유의미한 변수에서는 imputation이 오히려 성능을 떨어뜨릴 수 있다.
결측 패턴이 의미 있는지 먼저 확인한 후, 전처리 여부를 판단하는 것이 올바른 순서다.
또한 금융 실무에서는 CB사 ↔ 금융기관 간 전문(API) 데이터에서 결측이 NaN이 아닌 9999999 같은 Special Value로 채워져 오는 경우가 흔하다. 이에 대한 상세한 내용은 XGBoost와 LightGBM에서 다룬다.
sklearn Random Forest의 제약¶
sklearn의 RandomForestClassifier는 NaN 입력을 지원하지 않는다. RF를 사용하려면 사전에 결측치를 처리해야 한다.
| 방법 | 설명 | 주의점 |
|---|---|---|
| 중앙값/최빈값 대체 | 가장 단순한 방법 | 결측 패턴 정보 소실 |
| 결측 플래그 추가 | 별도 이진 변수 X_missing 생성 |
변수 수 증가, 트리가 이 플래그를 활용할 수 있음 |
| -9999 등 특수값 대체 | 결측을 극단값으로 대체 | 트리가 split으로 자연스럽게 분리 — 실무에서 흔히 사용 |
6.5 이상치 처리¶
트리 모형에서 이상치가 덜 위험한 이유¶
로지스틱 회귀에서 이상치는 회귀 계수(β)를 왜곡할 수 있다. 하지만 트리의 split은 순서 기반이므로, 극단적으로 큰 값이 있어도 "그 값이 큰 쪽" 그룹에 들어갈 뿐 다른 분할에는 영향을 미치지 않는다.
DTI 값: [10, 20, 30, 40, 50, 60, 999]
트리 split: DTI > 35?
→ 왼쪽: [10, 20, 30] | 오른쪽: [40, 50, 60, 999]
DTI=999가 DTI=60000이어도 분할 결과는 동일하다. 이것이 트리가 이상치에 강건(robust)한 이유다.
그래도 처리가 필요한 경우¶
| 상황 | 이유 | 대응 |
|---|---|---|
| 이상치가 데이터 입력 오류 | 잘못된 값이 모형에 의미 없는 리프를 생성 | 원천 데이터 수정 또는 capping |
| float32 정밀도 한계 | 극단적으로 큰 값에서 인접한 값을 구분 못함 | Capping 또는 binning |
| Feature Importance 왜곡 | 이상치가 있는 변수에서 split이 과도하게 발생 | 도메인 기반 판단 후 capping |
다음 섹션
이상치 처리까지 이해했으니, 다음으로 피처 선택 · 파생변수에서 Feature Importance, SHAP, Boruta 등 ML 기반 변수 선택 방법과 도메인 지식 기반 파생변수 생성을 다룬다.