불균형 데이터에서 비용 민감 학습과 EasyEnsemble 활용법

불균형 데이터 분류에서 Cost-Sensitive Learning과 EasyEnsemble을 적용해 기대 비용, 확률 보정, 임곗값을 운영하는 방법

2026-08-14 · 최초 발행 2024-04-29

희소 이벤트에서는 정확도보다 오분류 비용이 먼저다

사기 탐지, 이상 징후 감지, 의료 진단처럼 양성 사례가 적은 문제에서는 단순 정확도가 의사결정의 손실을 설명하지 못한다. 놓친 양성(FN)과 잘못 올린 경보(FP)의 비용이 다르기 때문이다.

이 글은 불균형 데이터 분류에 쓰는 Cost-Sensitive Learning과 EasyEnsemble을 중심으로, 비용 행렬·확률 보정·임곗값 관리와 운영상 주의점을 정리한다. 영어 토픽명은 “Advanced Imbalanced Learning: Cost-Sensitive Learning, EasyEnsemble”이다.

비용을 학습과 판정에 반영하는 방법

Cost-Sensitive Learning은 오분류 비용의 비대칭성을 모델과 학습 과정에 넣는 방식이다. 비용 행렬(Cost Matrix)을 정한 뒤 손실 가중치, 샘플 가중치, 임곗값 이동(threshold moving)을 사용해 기대 비용을 낮춘다.

양성으로 예측하는 기본 조건은 p(y=1|x) > t이며, 임곗값은 다음처럼 비용만으로 정할 수 있다.

t = C_FP / (C_FP + C_FN)

예를 들어 C_FN=20, C_FP=1이면 t = 1 / (1 + 20) = 1/21 ≈ 0.0476이다. 계산 과정은 1+20=21, 1/21≈0.0476으로 확인할 수 있다.

학습기에서는 class_weight 또는 sample_weight로 비용을 반영할 수 있다. 로지스틱 회귀와 선형 모델, 트리 계열이 이 방식을 폭넓게 지원한다. Cross-entropy에 비용 가중치를 적용하거나, γ를 조절하는 Focal loss로 어려운 샘플에 더 집중하는 변형도 가능하다.

EasyEnsemble이 다수 클래스 정보를 다루는 방식

EasyEnsemble은 다수 클래스에서 여러 균형 하위셋을 무작위 언더샘플링으로 만든 뒤, 각 하위셋에 AdaBoost 계열 약한 학습기를 학습시키고 결과를 집계하는 앙상블 기법이다.

단순 리샘플링인 SMOTE 또는 언더샘플링과 비교하면, 다수 클래스의 정보를 한 번에 버리지 않고 여러 하위셋에 나눠 사용한다. 이 과정은 정보 손실과 분산을 완화하고 과적합 억제를 함께 노린다. 반면 Cost-Sensitive Learning은 데이터 분포를 바꾸지 않고 손실과 임곗값을 조절해 기대 비용을 최소화한다.

EasyEnsemble에서는 n_estimators, 각 부스팅 단계의 약한 학습기 깊이와 수, 샘플 크기를 데이터 규모와 희소성에 맞춰 조정한다. 일반적인 흐름은 다수 클래스 랜덤 언더샘플링, 하위셋별 AdaBoost 학습, 확률 또는 결정값 평균·투표 순서다.

검증과 운영에서 놓치기 쉬운 조건

불균형 분류에서는 AUC-PR, 소수 클래스 F1, Recall@K, Balanced Accuracy, 기대 비용(Expected Cost)을 함께 본다. 검증은 Stratified K-Fold와 파이프라인 기반 전처리를 사용하고, Platt 또는 Isotonic 방식의 확률 보정(Calibration)을 적용해 데이터 누수를 막아야 한다.

운영 환경에서는 시드를 고정하고 데이터 버전을 관리한다. 비용 행렬이 바뀌면 임곗값을 다시 최적화하는 흐름도 자동화 대상이다. 사전 확률 이동, AUC-PR 하락, 기대 비용 상승을 성능 드리프트 신호로 감시하고 롤백 전략을 준비한다.

Cost-SensitiveEasyEnsemble기준 충족미달입력: Imbalanced DatasetEDA Stratified Split전략 선택가중 손실/샘플 가중치로 학습반복 언더샘플링 + AdaBoost앙상블확률 보정(CalibratedClassifierCV)비용 기반 임곗값 최적화 t =C_FP/(C_FP+C_FN)검증: AUC-PR, 기대 비용배포: 임곗값/비용 매개변수관리오류/리스크 감지데이터 누수확률 미보정클래스 붕괴/과적합

카드 사기·설비 고장·의료 신호에 적용할 때

카드 사기 탐지에서는 양성 비율이 0.2% 이하이고 FN 비용이 FP의 30배인 상황을 전제로 할 수 있다. 비용 행렬을 합의한 뒤 비용 가중 로지스틱 또는 LightGBM을 학습하고, 확률 보정 후 t= C_FP/(C_FP+C_FN) 임곗값을 적용해 운영 큐의 2차 심사와 연결한다. 경보량 제약은 Recall@AlertQuota로 관리하고 월별 비용·효익 보고를 자동화한다.

예지 정비에서는 고장 데이터가 희소하고 센서가 다차원인 조건이 흔하다. EasyEnsemble로 다수 클래스 언더샘플링의 변동성을 완화하고, 부스팅 기반 중요 변수 탐지와 기간 기반 rolling 검증으로 시간 누수를 막는다. 경보 묶음(batching)과 유지보수 창구 비용에 맞춰 임곗값을 다시 조정한다.

의료 이상 징후 탐지는 FP 비용은 낮고 FN 비용이 매우 큰 상황을 전제로 한다. 비용 민감 모델과 극저 임곗값을 사용하되, 전문가 판독을 통한 2차 검증 파이프라인을 둔다. 환자군 분포 변화인 케이스 믹스를 모니터링하고 교정(calibration)을 주기적으로 재학습한다.

비용 기반 분류와 EasyEnsemble 구현 예시

전제 조건은 Python 3.10+, scikit-learn 1.3+, imbalanced-learn 0.12+, numpy/pandas이며 환경 시드를 고정한다. 비용은 C_FP=1, C_FN=20으로 두고 이론 임곗값은 t≈0.0476으로 둔다.

# pip install scikit-learn==1.3.2 imbalanced-learn==0.12.3 numpy pandas

import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.calibration import CalibratedClassifierCV
from sklearn.metrics import average_precision_score, precision_recall_fscore_support
from imblearn.ensemble import EasyEnsembleClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

RANDOM_STATE = 42
C_FP, C_FN = 1.0, 20.0
THEORETICAL_T = C_FP / (C_FP + C_FN)  # 1 / (1 + 20) = 0.0476...

X, y = make_classification(
    n_samples=100_000, n_features=20, n_informative=6, n_redundant=4,
    weights=[0.995, 0.005], flip_y=0.0, random_state=RANDOM_STATE
)

X_tr, X_te, y_tr, y_te = train_test_split(
    X, y, test_size=0.3, stratify=y, random_state=RANDOM_STATE
)

def pick_threshold_by_expected_cost(prob, y_true, c_fp=1.0, c_fn=20.0, grid=1001):
    # 기대 비용 = c_fp * FP + c_fn * FN (정규화: 표본 수로 나눔)
    ts = np.linspace(0.0, 1.0, grid)
    best_t, best_cost = 0.5, np.inf
    for t in ts:
        y_pred = (prob >= t).astype(int)
        fp = np.sum((y_pred == 1) & (y_true == 0))
        fn = np.sum((y_pred == 0) & (y_true == 1))
        cost = (c_fp * fp + c_fn * fn) / len(y_true)
        if cost < best_cost:
            best_cost, best_t = cost, t
    return best_t, best_cost

# 1) Cost-Sensitive Logistic Regression + Calibration
logit_pipe = Pipeline([
    ("scale", StandardScaler(with_mean=False)),  # 희소/고차원 안전세팅
    ("clf", LogisticRegression(
        solver="liblinear",
        class_weight={0: C_FP, 1: C_FN},  # 비용을 가중치로 근사
        random_state=RANDOM_STATE,
        max_iter=200
    ))
])

calibrated = CalibratedClassifierCV(logit_pipe, method="isotonic", cv=3)
calibrated.fit(X_tr, y_tr)
proba = calibrated.predict_proba(X_te)[:, 1]

t_data, data_cost = pick_threshold_by_expected_cost(proba, y_te, C_FP, C_FN)
t_final = max(t_data, THEORETICAL_T)  # 보수적 선택: 데이터 기반 t와 이론 t 중 큰 값

y_pred = (proba >= t_final).astype(int)
ap = average_precision_score(y_te, proba)
prec, rec, f1, _ = precision_recall_fscore_support(y_te, y_pred, average="binary", zero_division=0)

print(f"[Cost-Sensitive] AUC-PR={ap:.4f}, P={prec:.4f}, R={rec:.4f}, F1={f1:.4f}, t={t_final:.4f}")

# 2) EasyEnsembleClassifier
ee = EasyEnsembleClassifier(
    n_estimators=10,       # 앙상블 개수
    random_state=RANDOM_STATE
)
ee.fit(X_tr, y_tr)
proba_ee = ee.predict_proba(X_te)[:, 1]
t_ee, ee_cost = pick_threshold_by_expected_cost(proba_ee, y_te, C_FP, C_FN)
y_pred_ee = (proba_ee >= t_ee).astype(int)

ap_ee = average_precision_score(y_te, proba_ee)
prec_ee, rec_ee, f1_ee, _ = precision_recall_fscore_support(y_te, y_pred_ee, average="binary", zero_division=0)

print(f"[EasyEnsemble] AUC-PR={ap_ee:.4f}, P={prec_ee:.4f}, R={rec_ee:.4f}, F1={f1_ee:.4f}, t={t_ee:.4f}")

스케일링, 특징 선택, SMOTE 같은 전처리는 학습 Fold 안에서만 수행한다. 임곗값을 최적화하기 전에는 확률 보정이 필요하며, class_weight를 무한대에 가깝게 키우거나 극단적으로 설정하면 발산 위험이 있으므로 조정해야 한다.

성능과 운영 특성 비교

항목 Cost-Sensitive Learning EasyEnsemble
성능(소수 클래스 재현율/Expected Cost) 비용 명시와 임곗값 최적화로 기대 비용 최소화에 유리 희소 이벤트 탐지가 안정적이며 AUC-PR·재현율 향상 경향
확장성(데이터 규모) 선형·트리·GBM 등 선택지가 넓고 대규모에도 유연 n_estimators와 부스팅 반복으로 비용이 증가하며 병렬화로 완화 가능
일관성(폴드 간 분산) 확률 보정 품질에 좌우 다중 언더샘플 앙상블로 분산 완화 효과
안정성(데이터 드리프트) 비용과 임곗값 재튜닝으로 대응하기 용이 샘플 분포 변동에 비교적 견고하나 재학습 필요
운영 편의 임곗값과 비용 변경만으로 운영 제약을 반영하기 쉬움 파이프라인이 복잡하고 재현성 관리 필요

비용을 C_FP=1, C_FN=20으로 가정하면, 임곗값 최적화는 FN 감소에 따라 총 비용을 10~40% 절감할 수 있다. 효과는 도메인과 기저성능에 의존한다. AUC-PR, Recall@K, 소수 클래스 F1의 유의한 향상도 기대할 수 있다.

비용 행렬과 임곗값은 사업적 합의를 드러내는 장치가 된다. 경보량이나 리소스 제약이 바뀌었을 때 임곗값을 빠르게 다시 설정할 수 있다는 점도 운영상 장점이다.

비용 행렬 합의, 확률 보정, 임곗값 최적화 자동화, 기대 비용 모니터링을 연결해 관리한다. EasyEnsemble에서는 n_estimators를 늘리되 랜덤 시드와 특징 서브샘플링으로 하위셋 다양성을 확보하고 과적합을 감시한다. 교차검증에서는 AUC-PR, Expected Cost, Recall@K를 일관된 지표 세트로 사용한다.

Cost-Sensitive Learning은 비용 설정에 민감하므로 비용 추정이 잘못되면 최적화 방향도 왜곡된다. EasyEnsemble은 계산량과 구현 복잡도를 높이며, 추론 지연 역시 관리 대상이다. 두 접근은 비용 기반 학습·보정·임곗값 관리와 EasyEnsemble의 강건성을 결합하는 방식으로 함께 사용할 수 있다.

불균형 데이터비용 민감 학습EasyEnsemble앙상블 학습이상 탐지