ericjedha commited on
Commit
2a409ff
·
verified ·
1 Parent(s): dbb9f1a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +231 -2
app.py CHANGED
@@ -5,6 +5,7 @@ import plotly.graph_objects as go
5
  from sqlalchemy import create_engine, text
6
  from datetime import datetime, timedelta
7
  import os
 
8
 
9
  # ========================== CONFIGURATION ==========================
10
  st.set_page_config(
@@ -45,6 +46,18 @@ def get_db_connection():
45
  st.stop()
46
 
47
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  # ========================== REQUÊTES SQL OPTIMISÉES ==========================
49
  def load_all_data():
50
  """Charge toutes les transactions - APPELÉ SEULEMENT APRÈS CLIC SUR REFRESH"""
@@ -240,6 +253,217 @@ def page_dashboard():
240
  else:
241
  st.info("Pas encore de données sur 7 jours")
242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  # ========================== PAGE: FRAUDES (24h) ==========================
244
  def page_frauds():
245
  st.title("🚨 Fraudes Détectées (Dernières 24h)")
@@ -323,7 +547,7 @@ def main():
323
  st.sidebar.title("Navigation")
324
  page = st.sidebar.radio(
325
  "Go to",
326
- ["🏠 Dashboard", "🚨 Fraudes (24h)", "✅ Non Fraudes (24h)"]
327
  )
328
 
329
  st.sidebar.markdown("---")
@@ -335,11 +559,16 @@ def main():
335
 
336
  **⚡ Optimisé** : Les données ne se chargent que sur demande pour économiser les ressources.
337
 
338
- **📊 Données** : Dernières 24h pour les pages de détail.
 
 
 
339
  """)
340
 
341
  if page == "🏠 Dashboard":
342
  page_dashboard()
 
 
343
  elif page == "🚨 Fraudes (24h)":
344
  page_frauds()
345
  elif page == "✅ Non Fraudes (24h)":
 
5
  from sqlalchemy import create_engine, text
6
  from datetime import datetime, timedelta
7
  import os
8
+ from skimpy import skim
9
 
10
  # ========================== CONFIGURATION ==========================
11
  st.set_page_config(
 
46
  st.stop()
47
 
48
 
49
+ # ========================== CHARGEMENT DES DONNÉES ==========================
50
+ @st.cache_data(ttl=3600)
51
+ def load_csv_data():
52
+ """Charge le fichier CSV pour l'EDA"""
53
+ try:
54
+ df = pd.read_csv("fraudTest.csv")
55
+ return df
56
+ except Exception as e:
57
+ st.error(f"❌ Erreur lors du chargement du fichier CSV: {e}")
58
+ return pd.DataFrame()
59
+
60
+
61
  # ========================== REQUÊTES SQL OPTIMISÉES ==========================
62
  def load_all_data():
63
  """Charge toutes les transactions - APPELÉ SEULEMENT APRÈS CLIC SUR REFRESH"""
 
253
  else:
254
  st.info("Pas encore de données sur 7 jours")
255
 
256
+
257
+ # ========================== PAGE: EDA ==========================
258
+ def page_eda():
259
+ st.title("📊 Exploratory Data Analysis")
260
+
261
+ st.info("👇 Cliquez sur **Load Data** pour charger les données EDA")
262
+
263
+ if st.button("🔄 Load Data", type="primary", key="eda_refresh"):
264
+ st.session_state.eda_loaded = True
265
+
266
+ if not st.session_state.get('eda_loaded', False):
267
+ st.warning("⚠️ Cliquez sur 'Load Data' pour afficher l'analyse")
268
+ return
269
+
270
+ with st.spinner("Chargement des données..."):
271
+ df = load_csv_data()
272
+
273
+ if df.empty:
274
+ st.error("Impossible de charger les données")
275
+ return
276
+
277
+ # ========================== 1. RÉSUMÉ AVEC SKIMPY ==========================
278
+ st.markdown("## 📋 Résumé des données avec Skimpy")
279
+
280
+ # Capturer la sortie de skim dans un buffer
281
+ import io
282
+ from contextlib import redirect_stdout
283
+
284
+ buffer = io.StringIO()
285
+ with redirect_stdout(buffer):
286
+ skim(df)
287
+
288
+ skim_output = buffer.getvalue()
289
+ st.text(skim_output)
290
+
291
+ st.markdown("---")
292
+
293
+ # ========================== 2. DISTRIBUTION FRAUDE vs NON-FRAUDE ==========================
294
+ st.markdown("## 🥧 Distribution des transactions")
295
+
296
+ fraud_counts = df["is_fraud"].value_counts().reset_index()
297
+ fraud_counts.columns = ["is_fraud", "count"]
298
+ fraud_counts["label"] = fraud_counts["is_fraud"].map({0: "Non frauduleuse", 1: "Frauduleuse"})
299
+
300
+ fig_pie = px.pie(
301
+ fraud_counts,
302
+ values="count",
303
+ names="label",
304
+ title="Répartition des transactions : frauduleuses vs non frauduleuses",
305
+ color_discrete_sequence=["#636EFA", "#EF553B"],
306
+ hole=0.4
307
+ )
308
+ fig_pie.update_traces(textinfo="percent+label")
309
+ st.plotly_chart(fig_pie, use_container_width=True)
310
+
311
+ # Statistiques
312
+ col1, col2, col3 = st.columns(3)
313
+ with col1:
314
+ st.metric("Total transactions", f"{len(df):,}")
315
+ with col2:
316
+ st.metric("Fraudes", f"{fraud_counts[fraud_counts['is_fraud']==1]['count'].values[0]:,}")
317
+ with col3:
318
+ fraud_rate = (fraud_counts[fraud_counts['is_fraud']==1]['count'].values[0] / len(df)) * 100
319
+ st.metric("Taux de fraude", f"{fraud_rate:.2f}%")
320
+
321
+ st.markdown("---")
322
+
323
+ # ========================== 3. CARTE GÉOGRAPHIQUE ==========================
324
+ st.markdown("## 🗺️ Localisation géographique des transactions")
325
+
326
+ # Vérifier si les colonnes existent
327
+ if 'merch_lat' in df.columns and 'merch_long' in df.columns:
328
+ df_geo = df.dropna(subset=["merch_lat", "merch_long"])
329
+
330
+ # Option d'échantillonnage pour performance
331
+ sample_size = st.slider("Nombre de points à afficher", 1000, min(50000, len(df_geo)), 10000, step=1000)
332
+ df_sample = df_geo.sample(n=min(sample_size, len(df_geo)), random_state=42)
333
+
334
+ # Ajouter le label
335
+ df_sample["fraud_label"] = df_sample["is_fraud"].map({0: "Non frauduleuse", 1: "Frauduleuse"})
336
+
337
+ fig_map = px.scatter_mapbox(
338
+ df_sample,
339
+ lat="merch_lat",
340
+ lon="merch_long",
341
+ color="fraud_label",
342
+ color_discrete_map={"Non frauduleuse": "#636EFA", "Frauduleuse": "#EF553B"},
343
+ title=f"Localisation des transactions ({sample_size} points échantillonnés)",
344
+ mapbox_style="open-street-map",
345
+ zoom=3,
346
+ height=700,
347
+ hover_data=["amt", "category", "merchant"]
348
+ )
349
+
350
+ fig_map.update_layout(
351
+ legend_title_text="Type de transaction",
352
+ margin={"r":0,"t":50,"l":0,"b":0}
353
+ )
354
+
355
+ st.plotly_chart(fig_map, use_container_width=True)
356
+ else:
357
+ st.warning("⚠️ Les colonnes de géolocalisation (merch_lat, merch_long) ne sont pas disponibles dans le dataset")
358
+
359
+ st.markdown("---")
360
+
361
+ # ========================== 4. FRAUDES PAR GENRE ==========================
362
+ st.markdown("## ���� Analyse par genre")
363
+
364
+ if 'gender' in df.columns:
365
+ # Nombre de fraudes par genre
366
+ fraud_by_gender = df[df["is_fraud"] == 1]["gender"].value_counts().reset_index()
367
+ fraud_by_gender.columns = ["gender", "count"]
368
+ fraud_by_gender["gender_label"] = fraud_by_gender["gender"].map({"M": "Homme", "F": "Femme"})
369
+
370
+ col1, col2 = st.columns(2)
371
+
372
+ with col1:
373
+ fig_gender = px.bar(
374
+ fraud_by_gender,
375
+ x="gender_label",
376
+ y="count",
377
+ color="gender_label",
378
+ color_discrete_map={"Homme": "#1f77b4", "Femme": "#ff7f0e"},
379
+ title="Nombre de fraudes par genre",
380
+ labels={"count": "Nombre de fraudes", "gender_label": "Genre"},
381
+ text="count"
382
+ )
383
+ fig_gender.update_layout(showlegend=False)
384
+ st.plotly_chart(fig_gender, use_container_width=True)
385
+
386
+ with col2:
387
+ # Taux de fraude par genre
388
+ gender_stats = df.groupby('gender')['is_fraud'].agg(['sum', 'count']).reset_index()
389
+ gender_stats['fraud_rate'] = (gender_stats['sum'] / gender_stats['count']) * 100
390
+ gender_stats['gender_label'] = gender_stats['gender'].map({"M": "Homme", "F": "Femme"})
391
+
392
+ fig_rate = px.bar(
393
+ gender_stats,
394
+ x="gender_label",
395
+ y="fraud_rate",
396
+ color="gender_label",
397
+ color_discrete_map={"Homme": "#1f77b4", "Femme": "#ff7f0e"},
398
+ title="Taux de fraude par genre (%)",
399
+ labels={"fraud_rate": "Taux de fraude (%)", "gender_label": "Genre"},
400
+ text=gender_stats['fraud_rate'].apply(lambda x: f"{x:.2f}%")
401
+ )
402
+ fig_rate.update_layout(showlegend=False)
403
+ st.plotly_chart(fig_rate, use_container_width=True)
404
+ else:
405
+ st.warning("⚠️ La colonne 'gender' n'est pas disponible dans le dataset")
406
+
407
+ st.markdown("---")
408
+
409
+ # ========================== 5. PAIRPLOT INTERACTIF ==========================
410
+ st.markdown("## 🔍 Corrélations et distributions (Pairplot)")
411
+
412
+ st.info("📌 Sélectionnez les variables numériques à analyser (max 5 pour la performance)")
413
+
414
+ # Sélectionner les colonnes numériques
415
+ numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns.tolist()
416
+
417
+ # Retirer is_fraud de la liste
418
+ if 'is_fraud' in numeric_cols:
419
+ numeric_cols.remove('is_fraud')
420
+
421
+ # Limiter aux colonnes les plus pertinentes par défaut
422
+ default_cols = ['amt', 'city_pop', 'lat', 'long'][:4]
423
+ default_cols = [col for col in default_cols if col in numeric_cols]
424
+
425
+ selected_cols = st.multiselect(
426
+ "Choisissez les variables à analyser",
427
+ numeric_cols,
428
+ default=default_cols[:4],
429
+ max_selections=5
430
+ )
431
+
432
+ if selected_cols:
433
+ # Échantillonner pour la performance
434
+ sample_size_pair = min(1000, len(df))
435
+ df_pair = df[selected_cols + ['is_fraud']].sample(n=sample_size_pair, random_state=42)
436
+ df_pair['fraud_label'] = df_pair['is_fraud'].map({0: "Non frauduleuse", 1: "Frauduleuse"})
437
+
438
+ # Créer un scatter matrix
439
+ fig_pair = px.scatter_matrix(
440
+ df_pair,
441
+ dimensions=selected_cols,
442
+ color="fraud_label",
443
+ color_discrete_map={"Non frauduleuse": "#636EFA", "Frauduleuse": "#EF553B"},
444
+ title=f"Matrice de corrélation ({sample_size_pair} échantillons)",
445
+ height=800
446
+ )
447
+
448
+ fig_pair.update_traces(diagonal_visible=False, showupperhalf=False)
449
+ st.plotly_chart(fig_pair, use_container_width=True)
450
+
451
+ # Matrice de corrélation
452
+ st.markdown("### 📊 Matrice de corrélation")
453
+ corr_matrix = df[selected_cols].corr()
454
+
455
+ fig_corr = px.imshow(
456
+ corr_matrix,
457
+ text_auto='.2f',
458
+ color_continuous_scale='RdBu_r',
459
+ title="Matrice de corrélation",
460
+ aspect="auto"
461
+ )
462
+ st.plotly_chart(fig_corr, use_container_width=True)
463
+ else:
464
+ st.warning("⚠️ Veuillez sélectionner au moins une variable")
465
+
466
+
467
  # ========================== PAGE: FRAUDES (24h) ==========================
468
  def page_frauds():
469
  st.title("🚨 Fraudes Détectées (Dernières 24h)")
 
547
  st.sidebar.title("Navigation")
548
  page = st.sidebar.radio(
549
  "Go to",
550
+ ["🏠 Dashboard", "📊 EDA", "🚨 Fraudes (24h)", "✅ Non Fraudes (24h)"]
551
  )
552
 
553
  st.sidebar.markdown("---")
 
559
 
560
  **⚡ Optimisé** : Les données ne se chargent que sur demande pour économiser les ressources.
561
 
562
+ **📊 Données** :
563
+ - Dashboard: Stats temps r��el
564
+ - EDA: Analyse du dataset complet
565
+ - Détail: Dernières 24h
566
  """)
567
 
568
  if page == "🏠 Dashboard":
569
  page_dashboard()
570
+ elif page == "📊 EDA":
571
+ page_eda()
572
  elif page == "🚨 Fraudes (24h)":
573
  page_frauds()
574
  elif page == "✅ Non Fraudes (24h)":