""" =============================================================================== KENDİ YÖNTEMİMİZİ TEST ETME: "Bizim bölme de şişiriyor mu?" =============================================================================== SORU: Walk-forward validasyon gerçek dünyanın simülasyonudur. Hiçbir bölme stratejisi ondan daha gerçekçi olamaz. O zaman her stratejinin walk-forward'a yakınlığı = dürüstlük derecesi. TEST: Her stratejinin F1'ini walk-forward F1 ile karşılaştır. - Yakın (±%10) = dürüst tahmin - Çok üstünde (>%15) = şişirilmiş - Çok altında (<-%15) = aşırı pesimist =============================================================================== """ import os, json import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import seaborn as sns from sklearn.preprocessing import StandardScaler from sklearn.metrics import f1_score, roc_auc_score import lightgbm as lgb from sklearn.ensemble import RandomForestClassifier import xgboost as xgb import warnings warnings.filterwarnings('ignore') np.random.seed(42) FIGDIR = '/app/figures_proof' OUTDIR = '/app/results_proof' # ─── VERİ YÜKLEME ─── feat_df = pd.read_csv('/app/data/elliptic_txs_features.csv', header=None) class_df = pd.read_csv('/app/data/elliptic_txs_classes.csv') timesteps = feat_df.iloc[:, 1].values.astype(int) features = feat_df.iloc[:, 2:].values.astype(np.float32) label_map = {'1': 1, '2': 0, 'unknown': -1} labels = np.array([label_map[str(c)] for c in class_df['class'].values]) labeled_mask = labels >= 0 X = features[labeled_mask] y = labels[labeled_mask] ts = timesteps[labeled_mask] def train_eval(X_tr, y_tr, X_te, y_te, model_type='lgbm'): scaler = StandardScaler() X_tr_s = scaler.fit_transform(X_tr) X_te_s = scaler.transform(X_te) if model_type == 'lgbm': m = lgb.LGBMClassifier(n_estimators=300, max_depth=10, scale_pos_weight=10, random_state=42, n_jobs=-1, verbose=-1) elif model_type == 'rf': m = RandomForestClassifier(n_estimators=300, max_depth=15, class_weight='balanced', random_state=42, n_jobs=-1) elif model_type == 'xgb': m = xgb.XGBClassifier(n_estimators=300, max_depth=8, scale_pos_weight=10, random_state=42, n_jobs=-1, verbosity=0) m.fit(X_tr_s, y_tr) pred = m.predict(X_te_s) return f1_score(y_te, pred, zero_division=0) # ─── WALK-FORWARD (ALTIN STANDART) ─── print("=" * 70) print("WALK-FORWARD VALİDASYON (ALTIN STANDART)") print("=" * 70) wf_results_all = {} for model_type, model_name in [('lgbm', 'LightGBM'), ('rf', 'Random Forest'), ('xgb', 'XGBoost')]: wf_f1s = [] for test_start in range(10, 49, 3): tr_mask = ts < test_start te_mask = (ts >= test_start) & (ts < test_start + 3) if tr_mask.sum() < 50 or te_mask.sum() < 10 or len(np.unique(y[te_mask])) < 2: continue f1 = train_eval(X[tr_mask], y[tr_mask], X[te_mask], y[te_mask], model_type) wf_f1s.append(f1) wf_avg = np.mean(wf_f1s) wf_results_all[model_name] = wf_avg print(f" {model_name}: Walk-Forward ortalama F1 = {wf_avg:.4f}") # ─── ÖNCEKİ SONUÇLARI YÜKLE ─── topo_results = pd.read_csv('/app/results_topo/all_results.csv') # ─── KARŞILAŞTIRMA TABLOSU ─── print("\n" + "=" * 70) print("HER STRATEJİNİN WALK-FORWARD'A YAKINLIĞI") print("=" * 70) comparison_data = [] for model_name in ['LightGBM', 'Random Forest', 'XGBoost']: wf_f1 = wf_results_all[model_name] print(f"\n {model_name} (Walk-Forward F1 = {wf_f1:.4f}):") for _, row in topo_results[topo_results['model'] == model_name].iterrows(): strat = row['strategy'] f1 = row['f1'] diff = f1 - wf_f1 pct = (diff / wf_f1) * 100 abs_pct = abs(pct) if abs_pct < 10: durum = 'DÜRÜST ✓' elif pct > 15: durum = 'ŞİŞİRİYOR 🔴' elif pct > 10: durum = 'HAFİF YÜKSEK ⚠️' elif pct < -15: durum = 'ÇOK PESİMİST' else: durum = 'HAFİF DÜŞÜK' comparison_data.append({ 'Model': model_name, 'Strateji': strat, 'F1': f1, 'WF_F1': wf_f1, 'Fark': diff, 'Pct': pct, 'Durum': durum }) print(f" {strat:<30s} F1={f1:.4f} fark={diff:+.4f} ({pct:+.1f}%) {durum}") comp_df = pd.DataFrame(comparison_data) # ─── SONUÇ ─── print("\n" + "=" * 70) print("SONUÇ") print("=" * 70) # Her stratejinin ortalama sapması print("\nStratejilerin walk-forward'a ortalama sapması (tüm modeller):") for strat in comp_df['Strateji'].unique(): subset = comp_df[comp_df['Strateji'] == strat] avg_pct = subset['Pct'].mean() print(f" {strat:<30s}: ortalama {avg_pct:+.1f}%") # ─── FİGÜR ─── print("\nFİGÜR OLUŞTURULUYOR...") sns.set_theme(style='whitegrid', font_scale=1.1) fig, ax = plt.subplots(figsize=(16, 9)) strategies_order = ['Rastgele', 'Kronolojik', 'Topolojik Kırılma (Bizim)', 'Kayan Pencere', 'Düşmanca-Kriz'] models_order = ['LightGBM', 'Random Forest', 'XGBoost'] colors = {'LightGBM': '#4ECDC4', 'Random Forest': '#45B7D1', 'XGBoost': '#96CEB4'} x = np.arange(len(strategies_order)) width = 0.22 for i, model_name in enumerate(models_order): wf_f1 = wf_results_all[model_name] vals = [] for strat in strategies_order: row = comp_df[(comp_df['Model'] == model_name) & (comp_df['Strateji'] == strat)] vals.append(row['F1'].values[0] if len(row) > 0 else 0) bars = ax.bar(x + i * width, vals, width, label=model_name, color=colors[model_name], edgecolor='black', linewidth=0.5) # Walk-forward bandı wf_avg_all = np.mean(list(wf_results_all.values())) wf_min = min(wf_results_all.values()) wf_max = max(wf_results_all.values()) ax.axhspan(wf_min * 0.9, wf_max * 1.1, alpha=0.15, color='green', label='Walk-Forward bandı (±%10)') ax.axhline(y=wf_avg_all, color='green', linewidth=2, linestyle='--', label=f'Walk-Forward ort. F1={wf_avg_all:.3f}') ax.set_xticks(x + width) ax.set_xticklabels(strategies_order, rotation=15, ha='right', fontsize=11) ax.set_ylabel('Illicit F1 Score', fontsize=13) ax.set_title('Her Bölme Stratejisinin Walk-Forward\'a (Gerçek Dünya) Yakınlığı\n' 'Yeşil bant içinde = dürüst tahmin, üstünde = şişirilmiş', fontsize=14, fontweight='bold') ax.legend(fontsize=10, loc='upper right') ax.set_ylim(0, 1.1) ax.grid(axis='y', alpha=0.3) plt.tight_layout() plt.savefig(f'{FIGDIR}/fig6_honesty_test.png', dpi=150, bbox_inches='tight') plt.close() print(" ✓ Figür 6: Dürüstlük Testi") # JSON kaydet comp_df.to_csv(f'{OUTDIR}/honesty_comparison.csv', index=False) with open(f'{OUTDIR}/walk_forward_by_model.json', 'w') as f: json.dump({k: float(v) for k, v in wf_results_all.items()}, f, indent=2) print("\n✓ Tamamlandı!")