MucahitSylmz commited on
Commit
ebde55f
·
verified ·
1 Parent(s): e1cf902

Veri temizleme ve ön işleme analiz scripti eklendi (data_audit.py)"

Browse files
Files changed (1) hide show
  1. data_audit.py +361 -0
data_audit.py ADDED
@@ -0,0 +1,361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ===============================================================================
3
+ VERİ TEMİZLEME VE ÖN İŞLEME ANALİZİ
4
+ ===============================================================================
5
+
6
+ Bu script veri setini derinlemesine inceleyip şu soruları cevaplar:
7
+ 1. Eksik değer var mı?
8
+ 2. Outlier (aykırı değer) var mı?
9
+ 3. Özellik dağılımları nasıl?
10
+ 4. Sınıf dengesizliği ne kadar ciddi?
11
+ 5. Hangi temizleme/ön işleme adımları sonuçları iyileştirir?
12
+
13
+ KULLANIM:
14
+ python data_audit.py --data_dir ./dataset
15
+ ===============================================================================
16
+ """
17
+
18
+ import os, sys, argparse, warnings
19
+ import numpy as np
20
+ import pandas as pd
21
+ from collections import Counter
22
+
23
+ import matplotlib
24
+ matplotlib.use('Agg')
25
+ import matplotlib.pyplot as plt
26
+ import seaborn as sns
27
+
28
+ from sklearn.preprocessing import StandardScaler, RobustScaler, MinMaxScaler
29
+ from sklearn.ensemble import RandomForestClassifier, IsolationForest
30
+ from sklearn.model_selection import train_test_split
31
+ from sklearn.metrics import f1_score, classification_report
32
+ from sklearn.feature_selection import mutual_info_classif
33
+ from imblearn.over_sampling import SMOTE, ADASYN
34
+ from imblearn.under_sampling import RandomUnderSampler
35
+ from imblearn.combine import SMOTETomek
36
+ import lightgbm as lgb
37
+
38
+ warnings.filterwarnings('ignore')
39
+ np.random.seed(42)
40
+
41
+ def main(data_dir):
42
+ FIGDIR = os.path.join(data_dir, '..', 'audit_figures')
43
+ os.makedirs(FIGDIR, exist_ok=True)
44
+
45
+ # ─── VERİ YÜKLE ───
46
+ print("=" * 70)
47
+ print("1. VERİ YÜKLEME")
48
+ print("=" * 70)
49
+
50
+ feat_df = pd.read_csv(os.path.join(data_dir, 'elliptic_txs_features.csv'), header=None)
51
+ class_df = pd.read_csv(os.path.join(data_dir, 'elliptic_txs_classes.csv'))
52
+ edge_df = pd.read_csv(os.path.join(data_dir, 'elliptic_txs_edgelist.csv'))
53
+
54
+ txids = feat_df.iloc[:, 0].values
55
+ timesteps = feat_df.iloc[:, 1].values.astype(int)
56
+ features = feat_df.iloc[:, 2:].values
57
+
58
+ label_map = {'1': 1, '2': 0, 'unknown': -1}
59
+ labels = np.array([label_map[str(c)] for c in class_df['class'].values])
60
+
61
+ labeled_mask = labels >= 0
62
+ X = features[labeled_mask].astype(np.float64)
63
+ y = labels[labeled_mask]
64
+ ts = timesteps[labeled_mask]
65
+
66
+ print(f" Toplam: {len(features)}, Etiketli: {len(X)}")
67
+ print(f" Özellik sayısı: {X.shape[1]}")
68
+ print(f" Sınıf dağılımı: illicit={y.sum()} ({y.mean()*100:.1f}%), licit={len(y)-y.sum()}")
69
+
70
+ # ─── EKSİK DEĞER ANALİZİ ───
71
+ print("\n" + "=" * 70)
72
+ print("2. EKSİK DEĞER ANALİZİ")
73
+ print("=" * 70)
74
+
75
+ nan_count = np.isnan(X).sum()
76
+ inf_count = np.isinf(X).sum()
77
+ zero_cols = (X == 0).all(axis=0).sum()
78
+
79
+ print(f" NaN sayısı: {nan_count}")
80
+ print(f" Inf sayısı: {inf_count}")
81
+ print(f" Tamamen sıfır olan sütun: {zero_cols}")
82
+
83
+ # Her sütundaki NaN oranı
84
+ nan_per_col = np.isnan(X).sum(axis=0)
85
+ if nan_count > 0:
86
+ problematic = np.where(nan_per_col > 0)[0]
87
+ print(f" NaN içeren sütunlar: {len(problematic)}")
88
+ for col in problematic[:10]:
89
+ print(f" Sütun {col}: {nan_per_col[col]} NaN ({nan_per_col[col]/len(X)*100:.2f}%)")
90
+ else:
91
+ print(f" ✓ Eksik değer yok")
92
+
93
+ # ─── OUTLIER ANALİZİ ───
94
+ print("\n" + "=" * 70)
95
+ print("3. OUTLIER (AYKIRI DEĞER) ANALİZİ")
96
+ print("=" * 70)
97
+
98
+ # IQR yöntemi
99
+ Q1 = np.percentile(X, 25, axis=0)
100
+ Q3 = np.percentile(X, 75, axis=0)
101
+ IQR = Q3 - Q1
102
+ lower = Q1 - 1.5 * IQR
103
+ upper = Q3 + 1.5 * IQR
104
+
105
+ outlier_mask = (X < lower) | (X > upper)
106
+ outlier_per_col = outlier_mask.sum(axis=0)
107
+ outlier_per_row = outlier_mask.sum(axis=1)
108
+ total_outliers = outlier_mask.sum()
109
+
110
+ print(f" Toplam outlier hücre: {total_outliers} ({total_outliers/(X.shape[0]*X.shape[1])*100:.2f}%)")
111
+ print(f" En az 1 outlier'ı olan satır: {(outlier_per_row > 0).sum()} ({(outlier_per_row > 0).mean()*100:.1f}%)")
112
+ print(f" Ortalama outlier/satır: {outlier_per_row.mean():.1f}")
113
+
114
+ # En çok outlier içeren sütunlar
115
+ top_outlier_cols = np.argsort(-outlier_per_col)[:10]
116
+ print(f"\n En çok outlier içeren 10 sütun:")
117
+ for col in top_outlier_cols:
118
+ print(f" Sütun {col}: {outlier_per_col[col]} outlier ({outlier_per_col[col]/len(X)*100:.1f}%)")
119
+
120
+ # İllicit vs licit outlier karşılaştırması
121
+ ill_outliers = outlier_per_row[y == 1].mean()
122
+ lic_outliers = outlier_per_row[y == 0].mean()
123
+ print(f"\n İllicit örneklerin ortalama outlier sayısı: {ill_outliers:.1f}")
124
+ print(f" Licit örneklerin ortalama outlier sayısı: {lic_outliers:.1f}")
125
+ if ill_outliers > lic_outliers * 1.2:
126
+ print(f" ⚠️ İllicit örnekler {ill_outliers/lic_outliers:.1f}x daha fazla outlier içeriyor!")
127
+ print(f" Bu, outlier temizliğinin illicit sınıfını orantısız etkileyebileceği anlamına gelir.")
128
+
129
+ # ─── ÖZELLİK DAĞILIMI ANALİZİ ───
130
+ print("\n" + "=" * 70)
131
+ print("4. ÖZELLİK DAĞILIMI ANALİZİ")
132
+ print("=" * 70)
133
+
134
+ # Local vs Aggregated ayrımı
135
+ local_features = X[:, :93] # İlk 93: local özellikler (sütun 2-94)
136
+ agg_features = X[:, 93:] # Son 72: aggregated özellikler (sütun 95-166)
137
+
138
+ local_mean = np.mean(np.abs(local_features))
139
+ agg_mean = np.mean(np.abs(agg_features))
140
+ local_std = np.std(local_features)
141
+ agg_std = np.std(agg_features)
142
+
143
+ print(f" Local özellikler (93 adet):")
144
+ print(f" Ortalama |değer|: {local_mean:.4f}")
145
+ print(f" Standart sapma: {local_std:.4f}")
146
+ print(f" Min: {local_features.min():.4f}, Max: {local_features.max():.4f}")
147
+
148
+ print(f"\n Aggregated özellikler (72 adet):")
149
+ print(f" Ortalama |değer|: {agg_mean:.4f}")
150
+ print(f" Standart sapma: {agg_std:.4f}")
151
+ print(f" Min: {agg_features.min():.4f}, Max: {agg_features.max():.4f}")
152
+
153
+ # Varyansı çok düşük özellikler
154
+ variances = np.var(X, axis=0)
155
+ low_var = (variances < 1e-6).sum()
156
+ print(f"\n Varyansı çok düşük (< 1e-6) özellik: {low_var}")
157
+
158
+ # Yüksek korelasyonlu özellik çiftleri
159
+ corr_matrix = np.corrcoef(X.T)
160
+ np.fill_diagonal(corr_matrix, 0)
161
+ high_corr = (np.abs(corr_matrix) > 0.95).sum() // 2 # Üçgen matris
162
+ print(f" Yüksek korelasyonlu (|r|>0.95) özellik çifti: {high_corr}")
163
+
164
+ # ─── SINIF DENGESİZLİĞİ ANALİZİ ───
165
+ print("\n" + "=" * 70)
166
+ print("5. SINIF DENGESİZLİĞİ ANALİZİ")
167
+ print("=" * 70)
168
+
169
+ ratio = (y == 0).sum() / max((y == 1).sum(), 1)
170
+ print(f" Licit/İllicit oranı: {ratio:.1f}:1")
171
+ print(f" Bu çok ciddi bir dengesizlik.")
172
+
173
+ # Timestep bazında dengesizlik
174
+ print(f"\n Timestep bazında dengesizlik:")
175
+ for t in sorted(np.unique(ts))[:10]:
176
+ mask = ts == t
177
+ t_ill = y[mask].sum()
178
+ t_total = mask.sum()
179
+ t_rate = t_ill / max(t_total, 1) * 100
180
+ print(f" TS {t:2d}: {t_total:5d} örnek, {t_ill:4d} illicit ({t_rate:.1f}%)")
181
+ print(f" ... (49 timestep toplam)")
182
+
183
+ # ─── TEMİZLEME VE ÖN İŞLEME ETKİ TESTİ ───
184
+ print("\n" + "=" * 70)
185
+ print("6. TEMİZLEME VE ÖN İŞLEME ETKİ TESTİ")
186
+ print("=" * 70)
187
+ print(" Her adımın F1 skoruna etkisini test ediyoruz...")
188
+ print(" Temporal split kullanılıyor (TS 1-39 eğitim, 40-49 test)")
189
+
190
+ tr_mask = ts <= 39
191
+ te_mask = ts > 39
192
+
193
+ def eval_pipeline(X_tr, y_tr, X_te, y_te, name):
194
+ """LightGBM ile hızlı değerlendirme."""
195
+ model = lgb.LGBMClassifier(
196
+ n_estimators=300, max_depth=10, learning_rate=0.1,
197
+ scale_pos_weight=10, random_state=42, n_jobs=-1, verbose=-1
198
+ )
199
+ model.fit(X_tr, y_tr)
200
+ pred = model.predict(X_te)
201
+ f1 = f1_score(y_te, pred, zero_division=0)
202
+ return f1
203
+
204
+ results = {}
205
+
206
+ # Baseline: ham veri, scaling yok
207
+ print("\n [1/8] Baseline (ham veri)...")
208
+ f1_base = eval_pipeline(X[tr_mask], y[tr_mask], X[te_mask], y[te_mask], "baseline")
209
+ results['1. Ham Veri (Baseline)'] = f1_base
210
+ print(f" F1 = {f1_base:.4f}")
211
+
212
+ # StandardScaler
213
+ print(" [2/8] StandardScaler...")
214
+ scaler = StandardScaler()
215
+ X_ss = scaler.fit_transform(X[tr_mask]), scaler.transform(X[te_mask])
216
+ f1_ss = eval_pipeline(X_ss[0], y[tr_mask], X_ss[1], y[te_mask], "standard")
217
+ results['2. StandardScaler'] = f1_ss
218
+ print(f" F1 = {f1_ss:.4f} (fark: {f1_ss-f1_base:+.4f})")
219
+
220
+ # RobustScaler (outlier'lara dayanıklı)
221
+ print(" [3/8] RobustScaler...")
222
+ rscaler = RobustScaler()
223
+ X_rs = rscaler.fit_transform(X[tr_mask]), rscaler.transform(X[te_mask])
224
+ f1_rs = eval_pipeline(X_rs[0], y[tr_mask], X_rs[1], y[te_mask], "robust")
225
+ results['3. RobustScaler'] = f1_rs
226
+ print(f" F1 = {f1_rs:.4f} (fark: {f1_rs-f1_base:+.4f})")
227
+
228
+ # NaN temizleme + StandardScaler
229
+ print(" [4/8] NaN temizleme + StandardScaler...")
230
+ X_clean = np.nan_to_num(X, nan=0.0, posinf=0.0, neginf=0.0)
231
+ scaler2 = StandardScaler()
232
+ X_c = scaler2.fit_transform(X_clean[tr_mask]), scaler2.transform(X_clean[te_mask])
233
+ f1_c = eval_pipeline(X_c[0], y[tr_mask], X_c[1], y[te_mask], "clean")
234
+ results['4. NaN Temizleme + Standard'] = f1_c
235
+ print(f" F1 = {f1_c:.4f} (fark: {f1_c-f1_base:+.4f})")
236
+
237
+ # Outlier clipping + StandardScaler
238
+ print(" [5/8] Outlier Clipping (IQR)...")
239
+ X_clipped = np.clip(X, lower, upper)
240
+ scaler3 = StandardScaler()
241
+ X_cl = scaler3.fit_transform(X_clipped[tr_mask]), scaler3.transform(X_clipped[te_mask])
242
+ f1_cl = eval_pipeline(X_cl[0], y[tr_mask], X_cl[1], y[te_mask], "clipped")
243
+ results['5. Outlier Clipping + Standard'] = f1_cl
244
+ print(f" F1 = {f1_cl:.4f} (fark: {f1_cl-f1_base:+.4f})")
245
+
246
+ # SMOTE (oversampling)
247
+ print(" [6/8] SMOTE Oversampling...")
248
+ try:
249
+ smote = SMOTE(random_state=42)
250
+ X_tr_sm, y_tr_sm = smote.fit_resample(X_clean[tr_mask], y[tr_mask])
251
+ scaler4 = StandardScaler()
252
+ X_sm_tr = scaler4.fit_transform(X_tr_sm)
253
+ X_sm_te = scaler4.transform(X_clean[te_mask])
254
+ f1_sm = eval_pipeline(X_sm_tr, y_tr_sm, X_sm_te, y[te_mask], "smote")
255
+ results['6. SMOTE + Standard'] = f1_sm
256
+ print(f" F1 = {f1_sm:.4f} (fark: {f1_sm-f1_base:+.4f})")
257
+ except Exception as e:
258
+ print(f" SMOTE başarısız: {e}")
259
+ results['6. SMOTE + Standard'] = 0
260
+
261
+ # Düşük varyans özellik çıkarma
262
+ print(" [7/8] Düşük Varyans Özellik Çıkarma...")
263
+ var_mask = variances > 1e-6
264
+ X_var = X_clean[:, var_mask]
265
+ scaler5 = StandardScaler()
266
+ X_v = scaler5.fit_transform(X_var[tr_mask]), scaler5.transform(X_var[te_mask])
267
+ f1_v = eval_pipeline(X_v[0], y[tr_mask], X_v[1], y[te_mask], "var_filter")
268
+ results[f'7. Düşük Varyans Çıkarma ({var_mask.sum()} feat)'] = f1_v
269
+ print(f" F1 = {f1_v:.4f} (fark: {f1_v-f1_base:+.4f})")
270
+
271
+ # Tam pipeline: NaN + Outlier Clip + RobustScaler + SMOTE
272
+ print(" [8/8] Tam Pipeline: Temizle + Clip + RobustScale + SMOTE...")
273
+ try:
274
+ X_full = np.nan_to_num(X, nan=0.0, posinf=0.0, neginf=0.0)
275
+ X_full = np.clip(X_full, lower, upper)
276
+ rscaler2 = RobustScaler()
277
+ X_full_tr = rscaler2.fit_transform(X_full[tr_mask])
278
+ X_full_te = rscaler2.transform(X_full[te_mask])
279
+ smote2 = SMOTE(random_state=42)
280
+ X_full_tr_sm, y_full_tr_sm = smote2.fit_resample(X_full_tr, y[tr_mask])
281
+ f1_full = eval_pipeline(X_full_tr_sm, y_full_tr_sm, X_full_te, y[te_mask], "full")
282
+ results['8. Tam Pipeline'] = f1_full
283
+ print(f" F1 = {f1_full:.4f} (fark: {f1_full-f1_base:+.4f})")
284
+ except Exception as e:
285
+ print(f" Tam pipeline başarısız: {e}")
286
+ results['8. Tam Pipeline'] = 0
287
+
288
+ # ─── ÖZET TABLO ───
289
+ print("\n" + "=" * 70)
290
+ print("7. ÖZET: TEMİZLEME ADIMLARININ ETKİSİ")
291
+ print("=" * 70)
292
+
293
+ print(f"\n {'Adım':<45s} {'F1':>8s} {'Fark':>10s}")
294
+ print(" " + "-" * 65)
295
+ for name, f1 in sorted(results.items()):
296
+ diff = f1 - f1_base
297
+ marker = " ✓ EN İYİ" if f1 == max(results.values()) else ""
298
+ print(f" {name:<45s} {f1:>8.4f} {diff:>+10.4f}{marker}")
299
+
300
+ best_name = max(results, key=results.get)
301
+ best_f1 = max(results.values())
302
+ print(f"\n En iyi pipeline: {best_name}")
303
+ print(f" Baseline'dan iyileşme: {best_f1 - f1_base:+.4f} ({(best_f1-f1_base)/f1_base*100:+.1f}%)")
304
+
305
+ # ─── FİGÜR ───
306
+ print("\nFigür oluşturuluyor...")
307
+ sns.set_theme(style='whitegrid', font_scale=1.0)
308
+
309
+ fig, axes = plt.subplots(2, 2, figsize=(16, 12))
310
+
311
+ # 1: Pipeline karşılaştırma
312
+ names = list(results.keys())
313
+ vals = list(results.values())
314
+ colors = ['#FF6B6B' if v == f1_base else '#4ECDC4' if v == best_f1 else '#45B7D1' for v in vals]
315
+ axes[0,0].barh(names, vals, color=colors)
316
+ axes[0,0].set_xlabel('Illicit F1 Score')
317
+ axes[0,0].set_title('Ön İşleme Adımlarının F1 Etkisi\n(Kırmızı=baseline, Yeşil=en iyi)')
318
+ axes[0,0].axvline(x=f1_base, color='red', linestyle='--', alpha=0.5)
319
+
320
+ # 2: Outlier dağılımı
321
+ axes[0,1].hist(outlier_per_row[y==0], bins=30, alpha=0.6, label='Licit', color='green', density=True)
322
+ axes[0,1].hist(outlier_per_row[y==1], bins=30, alpha=0.6, label='Illicit', color='red', density=True)
323
+ axes[0,1].set_xlabel('Outlier Sayısı / Satır')
324
+ axes[0,1].set_ylabel('Yoğunluk')
325
+ axes[0,1].set_title('Sınıf Bazında Outlier Dağılımı')
326
+ axes[0,1].legend()
327
+
328
+ # 3: Sınıf dağılımı
329
+ axes[1,0].bar(['Licit', 'Illicit'], [(y==0).sum(), (y==1).sum()], color=['green', 'red'])
330
+ axes[1,0].set_ylabel('Örnek Sayısı')
331
+ axes[1,0].set_title(f'Sınıf Dengesizliği ({ratio:.1f}:1)')
332
+
333
+ # 4: Özellik varyansları
334
+ axes[1,1].hist(np.log10(variances + 1e-10), bins=50, color='steelblue')
335
+ axes[1,1].set_xlabel('log10(Varyans)')
336
+ axes[1,1].set_ylabel('Özellik Sayısı')
337
+ axes[1,1].set_title('Özellik Varyans Dağılımı')
338
+ axes[1,1].axvline(x=np.log10(1e-6), color='red', linestyle='--', label='Düşük varyans eşiği')
339
+ axes[1,1].legend()
340
+
341
+ plt.tight_layout()
342
+ plt.savefig(os.path.join(FIGDIR, 'data_audit.png'), dpi=150, bbox_inches='tight')
343
+ plt.close()
344
+ print(f" ✓ {os.path.join(FIGDIR, 'data_audit.png')}")
345
+
346
+ # Sonuçları kaydet
347
+ pd.DataFrame([
348
+ {'adim': k, 'f1': v, 'fark': v - f1_base}
349
+ for k, v in results.items()
350
+ ]).to_csv(os.path.join(FIGDIR, '..', 'audit_results.csv'), index=False)
351
+
352
+ print("\n" + "=" * 70)
353
+ print("VERİ DENETİMİ TAMAMLANDI!")
354
+ print("=" * 70)
355
+
356
+
357
+ if __name__ == '__main__':
358
+ parser = argparse.ArgumentParser()
359
+ parser.add_argument('--data_dir', type=str, default='./dataset')
360
+ args = parser.parse_args()
361
+ main(args.data_dir)