EDA(2)에서 다음과 같은 패턴을 확인습니다.
✅ 결측 여부 자체가 예측 신호가 될 수 있다
✅ 반복 거래(uid_cnt)와 평균 대비 금액 편차(uid_amt_z)가 사기율과 관계됨
✅ 빈도 기반 인코딩이 모델 성능에 도움이 된다
하지만 이 대회는 모델 구성보다 검증 전략을 잘 잡는 것이 더 중요하다는 글을 보았습니다. 그래서 랜덤 K-Fold CV만 쓰면 리더보드 점수가 흔들리거나 현실 일반화가 잘 안 되는 경우가 많다는 보고가 있다.
그래서 모델링 할때는
📌 시간 기반 검증
📌 Adversarial Validation
을 먼저 세팅하고 그 위에 Baseline 모델을 구축하는 순서로 진행하였습니다.
1. 시간 기반 검증 (Time-based Validation)
1.1 왜 필요한가?
TransactionDT는 단순 숫자처럼 보이지만 실제로는 시간 흐름을 반영하는 변수다.
- 초반 데이터와 후반 데이터의 패턴이 다를 수 있고 사기 유형도 시간에 따라 변할 수 있다
랜덤 분할은 미래 데이터를 과거 학습에 섞는 꼴이 된다.
→ 현실적인 검증이 아니다.
1.2 검증 방식 설계
# 시간 순 정렬
df = df.sort_values('TransactionDT').reset_index(drop=True)
# 앞 80%를 train, 뒤 20%를 valid
split_idx = int(len(df) * 0.8)
train_df = df.iloc[:split_idx]
valid_df = df.iloc[split_idx:]
X_train = train_df[features]
y_train = train_df['isFraud']
X_valid = valid_df[features]
y_valid = valid_df['isFraud']
→ 과거 데이터로 학습하고 미래 데이터로 검증
→ 현실적인 비즈니스 시나리오와 유사
2. Adversarial Validation
2.1 왜 하는가?
IEEE-CIS는 train/test 분포 차이가 존재한다는 이야기가 많다. 그래서 다음 질문을 던진다.
“train과 test를 구분하는 모델을 만들 수 있는가?”
만약 쉽게 구분된다면 train에서 잘 맞춘 모델이 test에서는 무너질 가능성이 높다. Adversarial Validation 기법은 데이터 분석 대회에 존재하는 문제를 해결하기 위해 나왔는데 제공되는 훈련데이터와 테스트 데이터의 분포가 다를 경우 어떻게 예측할 것인가 에 대한 것이다.
Adversarial Validation 기법을 하기 위해서는 우선 두 데이터 세트 훈련데이터와 테스트 데이터에 본래 타겟 값과 다른 타겟 값을 설정한다. 그리고 훈련데이터와 테스트 데이터를 병합해서 두 데이터가 어디에 속하는지 예측하는 모델을 만드는 방법입니다.
2.2 Adversarial Validation 코드
train_df['is_test'] = 0
test_df['is_test'] = 1
adv_df = pd.concat([train_df, test_df], axis=0)
X_adv = adv_df[features]
y_adv = adv_df['is_test']
LightGBM으로 학습해서 AUC를 계산해보면
- 특정 id 계열 변수
- Device / 이메일 도메인 빈도형 변수
에서 train/test 차이가 관찰됐다.
→ 과도하게 분포 차가 큰 변수는 결측 플래그로만 쓰거나 특정 레이블 인코딩 계열 처리로 조정하는 방식으로 다음 단계 실험에 반영했다.
3. Baseline LightGBM 모델
이번 글에서는 시간 기반 검증 + Adversarial Validation 기반 조정 → Baseline 모델까지를 목표로 합니다.
3.1 LightGBM 기본 설정
import lightgbm as lgb
lgb_params = {
"objective": "binary",
"metric": "auc",
"boosting_type": "gbdt",
"learning_rate": 0.02,
"num_leaves": 256,
"subsample": 0.8,
"colsample_bytree": 0.8,
"reg_alpha": 0.1,
"reg_lambda": 0.1,
"scale_pos_weight": (len(y_train) - y_train.sum()) / y_train.sum(),
}
특징:
- learning_rate 낮춰서 안정적 학습
- num_leaves는 복잡한 패턴 대응
- 불균형은 scale_pos_weight로 보정
3.2 학습 & 평가 코드
model = lgb.LGBMClassifier(**lgb_params, random_state=42, n_estimators=5000)
model.fit(
X_train, y_train,
eval_set=[(X_valid, y_valid)],
eval_metric="auc",
early_stopping_rounds=200,
verbose=200
)
pred_valid = model.predict_proba(X_valid)[:, 1]
val_auc = roc_auc_score(y_valid, pred_valid)
print("Time-based Validation AUC:", val_auc)
결과:
- Time-based CV AUC → 실제로 Public LB와 더 일관성 있는 결과를 보여줌
- Random split CV 대비 점수 편차 감소
'Project' 카테고리의 다른 글
| [Team Project] 네이버 플레이스 광고/체험단 리뷰 판별 모델 개발 - EDA (2) (0) | 2026.01.19 |
|---|---|
| [Team Project] 네이버 플레이스 광고/체험단 리뷰 판별 모델 개발 - 아이디어 선정 (1) (0) | 2026.01.08 |
| [Kaggle] IEEE-CIS Fraud Detection - EDA (2) (0) | 2026.01.08 |
| [Kaggle] IEEE-CIS Fraud Detection - 이상거래 탐지 문제 정의와 데이터 구조 (1) (0) | 2026.01.08 |
HELLO WORLD
안녕하세요. 데이터로 말하는 분석가 모모입니다.
데이터를 구조화하고 분석하는 과정과 실무에 활용되는 도구 중심의 내용을 기록합니다.