
머신러닝 프로젝트를 진행하다 보면 High-cardinality(고차원) 카테고리 변수를 마주하게 됩니다. 예를 들어 우편번호, 기기 ID, 혹은 수천 개의 카테고리를 가진 상품 분류 등이 이에 해당합니다. 이러한 데이터를 처리할 때 일반적인 One-Hot Encoding을 사용하면 데이터 프레임의 차원이 폭발적으로 증가하여 메모리 부족 현상이 발생하거나, 모델의 학습 속도가 현저히 느려지는 문제가 발생합니다. 이러한 한계를 극복하기 위해 실무에서는 Target Encoding(Mean Encoding)을 자주 사용합니다. 하지만 Target Encoding은 타겟 변수의 정보를 직접 참조하기 때문에 데이터 누수(Data Leakage)와 오버피팅(Overfitting)에 매우 취약하다는 치명적인 단점이 있습니다. 본 가이드에서는 실무 개발자가 즉시 적용할 수 있는 타겟 인코딩의 오버피팅 방지 전략과 파이썬 구현 예제를 상세히 다룹니다.
1. 카테고리 인코딩 방식별 장단점 비교
다양한 인코딩 기법들 중 왜 타겟 인코딩이 고차원 데이터에서 선호되는지, 그리고 주의점은 무엇인지 아래 표를 통해 정리해 보았습니다.
| 구분 | One-Hot Encoding | Label Encoding | Target Encoding |
|---|---|---|---|
| 차원 증가 | 매우 높음 (범주 수만큼) | 없음 (1개 컬럼 유지) | 없음 (1개 컬럼 유지) |
| 순서 정보 | 없음 | 임의로 부여됨 (위험함) | 타겟과의 상관관계 반영 |
| 데이터 누수 위험 | 낮음 | 낮음 | 매우 높음 |
| 주요 단점 | 희소 행렬 문제, 연산 비용 | 숫자 간 관계성 오인 | 오버피팅 가능성 농후 |
| 권장 상황 | 저차원 범주형 데이터 | 트리 모델 기반 단순 처리 | 고차원 범주형 데이터 |
2. Target Encoding의 핵심 원리와 수식
Target Encoding의 기본 아이디어는 카테고리 $i$에 해당하는 타겟 값의 평균을 해당 카테고리의 인코딩 값으로 사용하는 것입니다. 기본적인 수식은 다음과 같습니다.
$$\hat{x}_i = E[y | x = x_i]$$
하지만 단순히 평균만을 사용할 경우, 샘플 수가 적은 카테고리에서 극단적인 값이 도출되어 모델이 특정 노이즈에 과적합됩니다. 이를 방지하기 위해 Smoothing(평활화) 기법을 결합한 수식을 실무에서 주로 사용합니다.
$$\mu = \frac{n \times \bar{x} + m \times w}{n + m}$$
- $n$: 해당 카테고리의 샘플 수
- $\bar{x}$: 해당 카테고리의 타겟 평균
- $m$: Weight(가중치/임계값)
- $w$: 전체 데이터의 타겟 평균(Global Mean)
3. 실무 적용을 위한 오버피팅 방지 Python 예제 (7가지)
아래 예제들은 category_encoders 라이브러리와 scikit-learn, 그리고 직접 구현 방식을 혼합하여 실무에서 바로 복사해 사용할 수 있도록 구성했습니다.
#1. Smoothing을 활용한 기본 Target Encoding
가장 기초적이면서 필수적인 방법입니다. 샘플 수가 적은 그룹의 영향을 전체 평균으로 희석시킵니다.
import pandas as pd
from category_encoders import TargetEncoder
# 샘플 데이터 생성
df = pd.DataFrame({
'category': ['A', 'A', 'B', 'B', 'C', 'A', 'B', 'C'],
'target': [1, 0, 1, 1, 0, 1, 0, 0]
})
# smoothing 파라미터를 통해 오버피팅 방지
# smoothing 값이 클수록 전체 평균에 가까워짐
encoder = TargetEncoder(cols=['category'], smoothing=10.0)
df['encoded'] = encoder.fit_transform(df['category'], df['target'])
print(df)
#2. K-Fold Target Encoding (Cross-Validation)
학습 데이터를 여러 개의 폴드로 나누어, 현재 폴드의 인코딩 값을 구할 때 해당 폴드의 타겟은 제외하는 방식입니다. 데이터 누수를 막는 가장 강력한 방법 중 하나입니다.
from sklearn.model_selection import KFold
import numpy as np
def kfold_target_encode(df, column, target, folds=5):
kf = KFold(n_splits=folds, shuffle=True, random_state=42)
df[column + '_encoded'] = np.nan
for train_idx, val_idx in kf.split(df):
# 학습용 데이터의 평균을 계산하여 검증용 데이터에 매핑
mean_target = df.iloc[train_idx].groupby(column)[target].mean()
df.loc[df.index[val_idx], column + '_encoded'] = df.loc[df.index[val_idx], column].map(mean_target)
# NaN 값은 전체 평균으로 채움
df[column + '_encoded'].fillna(df[target].mean(), inplace=True)
return df
df = kfold_target_encode(df, 'category', 'target')
#3. Leave-One-Out Encoding (LOOE)
자신을 제외한 나머지 행들의 타겟 평균을 구하는 방식입니다. 행마다 미세하게 다른 값이 부여되어 모델이 단순 암기하는 것을 방지합니다.
from category_encoders import LeaveOneOutEncoder
# LOOE 적용
loo_encoder = LeaveOneOutEncoder(cols=['category'])
df['loo_encoded'] = loo_encoder.fit_transform(df['category'], df['target'])
#4. Noise Injection (가우시안 노이즈 추가)
인코딩된 값에 미세한 무작위 노이즈를 추가하여 모델의 일반화 성능을 높입니다.
def add_noise(series, noise_level):
return series * (1 + noise_level * np.random.randn(len(series)))
encoder = TargetEncoder(cols=['category'])
encoded_values = encoder.fit_transform(df['category'], df['target'])
df['noisy_encoded'] = add_noise(encoded_values['category'], 0.05)
#5. M-Estimate Encoder
Smoothing의 단순화된 버전으로, 'm'이라는 단일 매개변수를 사용하여 인코딩의 보수적인 정도를 조절합니다.
from category_encoders import MEstimateEncoder
# m 값이 클수록 전체 평균에 의존 (더 보수적임)
me_encoder = MEstimateEncoder(cols=['category'], m=5.0)
df['m_estimate'] = me_encoder.fit_transform(df['category'], df['target'])
#6. Weight of Evidence (WoE) Encoding
금융권 신용평가 모델에서 주로 사용되는 기법으로, 타겟이 이진 분류일 때 각 범주가 타겟 변수에 미치는 통계적 유의성을 인코딩합니다.
from category_encoders import WOEEncoder
woe_encoder = WOEEncoder(cols=['category'])
df['woe_encoded'] = woe_encoder.fit_transform(df['category'], df['target'])
#7. CatBoost Encoder
CatBoost 알고리즘에서 사용하는 방식으로, 데이터의 순서(Ordered)에 따라 현재 시점 이전의 데이터만을 사용하여 타겟 평균을 계산합니다. 시계열적 성격이 있거나 순서가 중요한 데이터에서 탁월합니다.
from category_encoders import CatBoostEncoder
cb_encoder = CatBoostEncoder(cols=['category'])
df['catboost_encoded'] = cb_encoder.fit_transform(df['category'], df['target'])
4. 결론 및 요약
Target Encoding은 강력하지만 양날의 검과 같습니다. 실무에서 고차원 카테고리 변수를 해결할 때는 다음의 전략을 권장합니다.
- 데이터셋이 크고 범주가 많다면: Smoothing을 포함한
TargetEncoder또는MEstimateEncoder를 사용하세요. - 오버피팅이 심하게 우려된다면:
K-Fold방식이나CatBoostEncoder를 최우선으로 고려하세요. - 검증 단계: 반드시 인코딩 과정이 Cross-validation 루프 안에서 이루어지도록 설계하여 훈련 데이터의 정보가 검증 데이터로 새나가지 않게 하세요.
출처 및 참고문헌:
- Micci-Barreca, D. (2001). "A Preprocessing Scheme for High-Cardinality Categorical Attributes in Classification and Prediction Problems." SIGKDD Explorations.
- Scikit-learn Documentation: Categorical Encoding strategies.
- Category Encoders Python Library (v2.6.0) Official Guide.
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] 완벽한 ETL 파이프라인 구축을 위한 Great Expectations 데이터 스키마 검증 방법 3가지 및 해결책 (0) | 2026.04.23 |
|---|---|
| [PYTHON] 고차원 데이터 시각화를 위한 t-SNE vs UMAP 2가지 알고리즘 성능 및 해석 차이 해결 방법 (0) | 2026.04.23 |
| [PYTHON] 시계열 결측치 0으로 해결하는 MICE 알고리즘의 한계와 3가지 대안 방법 (0) | 2026.04.23 |
| [PYTHON] 효율적인 데이터 라벨링을 위한 Active Learning 샘플링 전략 7가지 해결 방법 (0) | 2026.04.23 |
| [PYTHON] 저작권 데이터 학습 모델의 법적 리스크 해결을 위한 7가지 관리 방법과 차이점 (0) | 2026.04.23 |