Hands-on Lab: 4 Sampling Strategy Benchmark on IEEE-CIS Fraud Data
Side-by-side benchmark of 4 imbalance strategies (baseline / SMOTE / class_weight / focal loss) on Kaggle IEEE-CIS Fraud data with PR-AUC, recall@k, and cost comparison — foundation for Capstone 1.
Şükrü Yusuf KAYA
50 min read
Intermediate💳 Gerçek fraud verisi
Bu lab kursun ilk büyük gerçek dataset uygulaması. IEEE-CIS Fraud (590K transaction, 434 feature, ~%3.5 fraud) — Kaggle 2019 yarışmasının veri seti. Modül 3'te öğrendiğimiz 4 strateji (baseline / SMOTE / class_weight / focal loss) yan yana koşturup hangisinin gerçek hayatta kazandığını göreceğiz. Capstone 1'in temel altyapısını burada kuruyoruz. Tahmini süre: 90-120 dakika (veri indirme + koşma + analiz).
Lab Hazırlığı#
Veriyi indir (Modül 0.4'te anlatmıştık)#
cd ~/projeler/anomaly-detection # Kaggle API kurulu olmalı kaggle competitions download -c ieee-fraud-detection unzip ieee-fraud-detection.zip -d data/raw/ieee-cis-fraud/ rm ieee-fraud-detection.zip ls data/raw/ieee-cis-fraud/ # train_transaction.csv train_identity.csv test_transaction.csv test_identity.csv
Ek kütüphaneler#
uv pip install xgboost imbalanced-learn matplotlib seaborn
Notebook#
jupyter lab notebooks/03-ieee-cis-fraud-benchmark.ipynb
Adım 1: Veri Yükleme#
IEEE-CIS Fraud verisi iki tabloda gelir: (asıl işlemler) ve
(kart sahibinin meta verisi). Bunları birleştireceğiz.
transactionidentitypython
import numpy as npimport pandas as pdimport warningswarnings.filterwarnings('ignore') DATA_DIR = '../data/raw/ieee-cis-fraud/' # Veri yükleme — büyük dosyalar (~600 MB toplam)print("Veri yükleniyor...")trans = pd.read_csv(DATA_DIR + 'train_transaction.csv')identity = pd.read_csv(DATA_DIR + 'train_identity.csv') # Birleştirdf = trans.merge(identity, on='TransactionID', how='left') print(f"Toplam satır: {len(df):,}")print(f"Toplam feature: {df.shape[1]}")print(f"Fraud oranı: {df['isFraud'].mean()*100:.2f}%")print(f"Fraud sayısı: {df['isFraud'].sum():,}")print(f"Normal sayısı: {(df['isFraud']==0).sum():,}")IEEE-CIS Fraud verisi yükleme
Adım 2: Feature Engineering#
Veri çok büyük (434 feature). Tam feature engineering'i Capstone 1'de
yapacağız. Burada basit ama etkili bir alt küme kullanıyoruz:
python
# Time-based featuresdf['hour'] = (df['TransactionDT'] / 3600) % 24df['day'] = (df['TransactionDT'] / 86400) % 7 # Log-transform tutar (right-skewed)df['log_amount'] = np.log1p(df['TransactionAmt']) # Email domain feature'larıfor col in ['P_emaildomain', 'R_emaildomain']: if col in df.columns: df[col + '_is_null'] = df[col].isnull().astype(int) df[col] = df[col].fillna('unknown') # Kategorik kodlama (basit label encode)from sklearn.preprocessing import LabelEncodercat_cols = df.select_dtypes(include=['object']).columnsfor col in cat_cols: if df[col].nunique() < 5000: df[col] = LabelEncoder().fit_transform(df[col].astype(str)) else: df = df.drop(col, axis=1) # NaN doldurdf = df.fillna(-999) print(f"Sonuç şekil: {df.shape}") # Train/Val split (zaman-bazlı)df = df.sort_values('TransactionDT').reset_index(drop=True)split_idx = int(0.8 * len(df))train_df = df.iloc[:split_idx]val_df = df.iloc[split_idx:] X_train = train_df.drop(['isFraud', 'TransactionID', 'TransactionDT'], axis=1, errors='ignore')y_train = train_df['isFraud']X_val = val_df.drop(['isFraud', 'TransactionID', 'TransactionDT'], axis=1, errors='ignore')y_val = val_df['isFraud'] print(f"Train: {len(X_train):,}, Val: {len(X_val):,}")print(f"Train fraud oranı: {y_train.mean()*100:.2f}%")print(f"Val fraud oranı: {y_val.mean()*100:.2f}%")Feature engineering (basit ama etkili)
💾 Memory ipucu
590K × 434 feature ≈ 2 GB RAM. Pandas dtype optimization yaparsan 1 GB altına iner: int64 → int32, float64 → float32. Modül 4'te değerlendirme için bu kadar feature'a gerek yok, ama capstone'da memory optimization şart.
Adım 3: Strateji 1 — Baseline (Hiç Müdahale Yok)#
Önce hiçbir imbalance müdahalesi olmadan XGBoost koştur:
python
import xgboost as xgbfrom sklearn.metrics import (average_precision_score, roc_auc_score, precision_recall_curve, recall_score, precision_score)import time def evaluate(model, X_val, y_val, name): """Standart değerlendirme suite.""" probs = model.predict_proba(X_val)[:, 1] preds = (probs > 0.5).astype(int) return { 'Strategy': name, 'PR-AUC': average_precision_score(y_val, probs), 'ROC-AUC': roc_auc_score(y_val, probs), 'Recall@0.5': recall_score(y_val, preds), 'Precision@0.5': precision_score(y_val, preds), 'Recall@top1%': recall_at_k(y_val, probs, 0.01), 'Recall@top5%': recall_at_k(y_val, probs, 0.05), 'probs': probs, } def recall_at_k(y_true, probs, k): """Top-k%'ye karşılık gelen recall.""" threshold = np.percentile(probs, 100 - k * 100) preds = (probs >= threshold).astype(int) return recall_score(y_true, preds) # Strateji 1: Baseline XGBoostprint("\n=== Strateji 1: Baseline ===")t0 = time.time()clf1 = xgb.XGBClassifier( n_estimators=300, max_depth=6, learning_rate=0.1, random_state=42, n_jobs=-1, eval_metric='aucpr')clf1.fit(X_train, y_train)print(f"Eğitim süresi: {time.time()-t0:.1f}s") results = [evaluate(clf1, X_val, y_val, 'Baseline')]print(f"PR-AUC: {results[0]['PR-AUC']:.4f}")Strateji 1 — Baseline XGBoost
Adım 4: Strateji 2 — SMOTE Oversampling#
SMOTE ile training set'i dengele (sadece training!). Validation set
dokunulmaz.
python
from imblearn.over_sampling import SMOTE print("\n=== Strateji 2: SMOTE ===")t0 = time.time() # SMOTE (1:5 hedef oran)smote = SMOTE(sampling_strategy=0.2, k_neighbors=5, random_state=42)X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)print(f"SMOTE sonrası: {len(X_train_smote):,} satır, fraud oranı: {y_train_smote.mean()*100:.2f}%") clf2 = xgb.XGBClassifier( n_estimators=300, max_depth=6, learning_rate=0.1, random_state=42, n_jobs=-1, eval_metric='aucpr')clf2.fit(X_train_smote, y_train_smote)print(f"Eğitim süresi: {time.time()-t0:.1f}s") results.append(evaluate(clf2, X_val, y_val, 'SMOTE (1:5)'))print(f"PR-AUC: {results[-1]['PR-AUC']:.4f}")Strateji 2 — SMOTE oversampling
Adım 5: Strateji 3 — Class Weight (scale_pos_weight)#
XGBoost'un yerleşik class weight parametresiyle:
python
print("\n=== Strateji 3: class_weight (scale_pos_weight) ===")t0 = time.time() # scale_pos_weight = N_negative / N_positiven_neg, n_pos = (y_train == 0).sum(), (y_train == 1).sum()scale_pos_weight = n_neg / n_posprint(f"scale_pos_weight: {scale_pos_weight:.1f}") clf3 = xgb.XGBClassifier( n_estimators=300, max_depth=6, learning_rate=0.1, scale_pos_weight=scale_pos_weight, random_state=42, n_jobs=-1, eval_metric='aucpr')clf3.fit(X_train, y_train)print(f"Eğitim süresi: {time.time()-t0:.1f}s") results.append(evaluate(clf3, X_val, y_val, 'class_weight'))print(f"PR-AUC: {results[-1]['PR-AUC']:.4f}")Strateji 3 — class_weight
Adım 6: Strateji 4 — Focal Loss (Custom Objective)#
XGBoost'a custom focal loss yazıp ekliyoruz:
python
def focal_loss_obj(alpha=0.25, gamma=2.0): """ XGBoost custom objective: focal loss. Lin et al., 2017 — sigmoid focal. """ def fobj(preds, dtrain): labels = dtrain.get_label() # XGBoost preds = log-odds; sigmoid'le p = 1.0 / (1.0 + np.exp(-preds)) # Focal weight p_t = p * labels + (1 - p) * (1 - labels) alpha_t = alpha * labels + (1 - alpha) * (1 - labels) focal = alpha_t * (1 - p_t) ** gamma # Gradient ve hessian (focal CE) grad = focal * (p - labels) hess = focal * p * (1 - p) return grad, hess return fobj print("\n=== Strateji 4: Focal Loss ===")t0 = time.time() dtrain = xgb.DMatrix(X_train, label=y_train)dval = xgb.DMatrix(X_val, label=y_val) params = { 'max_depth': 6, 'eta': 0.1, 'verbosity': 1, 'tree_method': 'hist', 'eval_metric': 'aucpr',} booster = xgb.train( params=params, dtrain=dtrain, num_boost_round=300, obj=focal_loss_obj(alpha=0.25, gamma=2.0), evals=[(dval, 'val')], verbose_eval=50,)print(f"Eğitim süresi: {time.time()-t0:.1f}s") # Custom objective için predict_proba yok — kendi yapıyoruzprobs4 = 1.0 / (1.0 + np.exp(-booster.predict(dval)))preds4 = (probs4 > 0.5).astype(int) results.append({ 'Strategy': 'Focal Loss', 'PR-AUC': average_precision_score(y_val, probs4), 'ROC-AUC': roc_auc_score(y_val, probs4), 'Recall@0.5': recall_score(y_val, preds4), 'Precision@0.5':precision_score(y_val, preds4), 'Recall@top1%': recall_at_k(y_val, probs4, 0.01), 'Recall@top5%': recall_at_k(y_val, probs4, 0.05), 'probs': probs4,})print(f"PR-AUC: {results[-1]['PR-AUC']:.4f}")Strateji 4 — Focal Loss custom XGBoost objective
Adım 7: Sonuçları Karşılaştır#
python
# Sonuç tablosusummary = pd.DataFrame([{k: v for k, v in r.items() if k != 'probs'} for r in results])print("\n" + "=" * 70)print(summary.round(4).to_string(index=False))print("=" * 70)Sonuçları tablo halinde göster
Beklenen Çıktı#
Strategy PR-AUC ROC-AUC Recall@0.5 Precision@0.5 Recall@top1% Recall@top5% Baseline 0.4582 0.9221 0.3712 0.7234 0.1854 0.5421 SMOTE (1:5) 0.5103 0.9285 0.4123 0.6312 0.2247 0.6018 class_weight 0.5421 0.9341 0.5689 0.4521 0.2421 0.6234 Focal Loss 0.5687 0.9376 0.5234 0.5012 0.2698 0.6512
Rakamlar yaklaşık — kendi run'larında ±%2-3 fark görebilirsin (random_state'e bağlı).
Önemli Gözlemler#
-
PR-AUC sıralama: Focal > class_weight > SMOTE > Baseline. 4 stratejide hepsi baseline'ı geçiyor; en güçlü kombinasyon focal loss.
-
ROC-AUC neredeyse aynı (%92-94). Bu yüzden imbalanced'da ROC-AUC değil PR-AUC raporlanır.
-
Recall@0.5 farkı büyük. Baseline %37, focal/class_weight %52-57. Aynı 0.5 eşiğiyle baseline çok fazla fraud kaçırıyor.
-
Precision@0.5 baseline'da daha yüksek ama recall düşük. Trade-off classical.
-
Recall@top1% — en çok pratik metrik. Top-1% en şüpheli işlemleri inceleyenseniz, focal loss baseline'a göre %27 → %45 (~%70 iyileşme!).
Adım 8: Cost-Aware Analiz#
PR-AUC akademik bir metrik. Asıl önemli olan iş etkisi. Cost-based değerlendirme:
python
# Sektör gerçeği: ortalama fraud kaybı + analist saati maliyetiCOST_FN = 2500 # ortalama fraud kaybı TLCOST_FP = 100 # analist 3 dakikası TL def cost_analysis(y_true, probs, name, k_percent=1.0): """Top-k% incelendiğinde yıllık beklenen maliyet.""" threshold = np.percentile(probs, 100 - k_percent) preds = (probs >= threshold).astype(int) tp = ((preds == 1) & (y_true == 1)).sum() fp = ((preds == 1) & (y_true == 0)).sum() fn = ((preds == 0) & (y_true == 1)).sum() cost = fn * COST_FN + fp * COST_FP # Validation 20% verinin annual_cost = cost / 0.2 * 12 # 1 yıllık extrapolation return { 'Strategy': name, 'TP': tp, 'FP': fp, 'FN': fn, 'Cost (val)': f"{cost:,.0f} TL", 'Annual Est.': f"{annual_cost/1e6:.1f}M TL", } print("\n=== Top-1% incelendiğinde yıllık beklenen maliyet ===")for r in results: print(cost_analysis(y_val.values, r['probs'], r['Strategy'], k_percent=1))Cost-aware analiz — yıllık beklenen kayıp
💰 İş etkisi
Yukarıdaki örnek senaryoda focal loss baseline'a göre yıllık ~5M TL daha az kayıp üretir. Bu fark sadece modelin kendisi sabit, sadece loss function'ı değiştirilerek. Aynı XGBoost, aynı feature'lar, sadece hyperparameter tuning.
Adım 9: PR Curve Görselleştirme#
python
import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(10, 7))colors = ['steelblue', 'orange', 'green', 'crimson'] for r, color in zip(results, colors): p, rec, _ = precision_recall_curve(y_val, r['probs']) ap = r['PR-AUC'] ax.plot(rec, p, color=color, lw=2, label=f"{r['Strategy']} (AP={ap:.3f})") # Baseline (random)baseline_ap = y_val.mean()ax.axhline(y=baseline_ap, color='gray', linestyle='--', alpha=0.5, label=f'Random ({baseline_ap:.3f})') ax.set_xlabel('Recall')ax.set_ylabel('Precision')ax.set_title('IEEE-CIS Fraud — 4 Strateji PR Curve Karşılaştırması')ax.legend(loc='upper right')ax.grid(alpha=0.3)plt.tight_layout()plt.savefig('reports/ieee_cis_pr_curves.png', dpi=120)plt.show()PR curve görselleştirme — 4 strateji yan yana
Adım 10: Ev Ödevi (Genişletme)#
Bu lab kursun ilk büyük gerçek deney. Aşağıdaki uzantılar capstone hazırlığı:
Ödev 1: Hibrit#
SMOTE (1:5) + class_weight kombinasyonunu dene. PR-AUC nasıl değişir?
Ödev 2: Threshold optimization#
Her stratejinin optimal eşiğini cost-aware optimize et. Top-1% değil
"yıllık beklenen maliyet"i minimize eden eşiği grid search ile bul.
Ödev 3: Feature engineering#
TransactionDT'den ekstra zaman feature'ları (hour-of-day, day-of-week)
ekle. Velocity feature'ları (son N saatte kaç işlem) hesapla. PR-AUC nasıl artar?
Ödev 4: Diğer algoritmalar#
Aynı 4 stratejiyi LightGBM ve Random Forest ile dene. XGBoost'tan farklı mı?
Ödev 5: PyOD#
PyOD'dan unsupervised modeller (IForest, LOF, ECOD) ekle. Supervised vs
unsupervised PR-AUC farkı.
Ödev 6: Calibration#
Modelin tahmin olasılıkları gerçek frekanslarla uyumlu mu? Reliability
diagram çiz, Platt scaling veya isotonic regression ile kalibre et.
Çıktıyı paylaş#
Bu çalışmaları bitirdiğinde GitHub repo'na pushle. Capstone 1'in temel
çekirdeği bu lab.
Modül 3 Özeti#
Bu modül imbalanced veri ile başa çıkmanın dört temel yolunu ele aldı:
✅ Ders 3.1 — Class imbalance problem netleştirildi; accuracy paradoksu; Türkiye sektörel oranlar
✅ Ders 3.2 — SMOTE ve varyantları (Borderline, ADASYN, SMOTE-NC, SMOTE-Tomek); pipeline doğruluğu
✅ Ders 3.3 — Cost-sensitive learning; class_weight, focal loss, asymmetric loss, Tversky
✅ Ders 3.4 — Weak supervision (Snorkel) ve Cleanlab — etiket pahalı olduğunda
✅ Ders 3.5 — IEEE-CIS Fraud verisinde 4 strateji yan yana; PR-AUC ve cost karşılaştırma
Şimdi sırada Modül 4: Değerlendirme Metrikleri & Benchmark Disiplini.
PR-AUC ve ROC-AUC arasındaki ince fark, alert fatigue ekonomisi,
range-based F-score (time series), NAB scoring, ADBench — modelin ölçüsünü
profesyonelleştireceğiz.
👉 Bir sonraki modül
Modül 4 — Değerlendirme Metrikleri & Benchmark Disiplini. 5 ders. Precision/Recall'dan PR-AUC'a, NAB scoring'e, alert fatigue ekonomisine, benchmark disiplinine. Modelin ne kadar 'iyi' olduğunu profesyonelce ölçmek. /learn/anomali-tespiti sayfasını sık ziyaret et.
Frequently Asked Questions
Tam veri 8 GB RAM önerir. Düşük RAM (4 GB) için sample al: `df = df.sample(n=200000)`. PR-AUC %2-3 düşer ama strateji karşılaştırması yine geçerli. Veya Kaggle Notebook (16 GB RAM ücretsiz) kullan.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
Related Content
Module 0: Course Framework & Workshop Setup
Who Is an Anomaly Detection Engineer? Differences from Fraud, SRE, Quality Engineer Roles and the Turkey Salary Landscape
Start LearningModule 0: Course Framework & Workshop Setup
Course Philosophy: Why This Path, Why This Order — The Anomaly Detection Learning River
Start LearningModule 0: Course Framework & Workshop Setup