Skip to content

Instantly share code, notes, and snippets.

@hdary85
Created April 10, 2025 16:31
Show Gist options
  • Select an option

  • Save hdary85/36b32bc0e7bcafdbed51dc9ea35b4fe6 to your computer and use it in GitHub Desktop.

Select an option

Save hdary85/36b32bc0e7bcafdbed51dc9ea35b4fe6 to your computer and use it in GitHub Desktop.
nmar
# 1. Import des librairies nécessaires
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import colors
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix, roc_curve, auc
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
# Pour afficher les graphiques dans un notebook (si besoin)
%matplotlib inline
# 2. Création du DataFrame avec quelques exemples
data = {
# Groupe 1: Informations sur l'alerte
'ALERT_ID': [1, 1, 1],
'ALERT_DATE': ['2024-02-01', '2024-02-01', '2024-02-01'],
# Groupe 2: Informations sur le party_key
'PARTY_RISK': [2, 2, 2],
'PARTY_KEY': [1234, 1234, 1234],
'PARTY_POPULATION_GROUP': ['VSB', 'VSB', 'VSB'],
# Groupe 3: Détails des transactions
'TRX_AMOUNT': [100, 150, 1000],
'TRX_DATE': ['2024-01-12', '2024-01-20', '2024-01-25'],
'TRX_TYPE': ['VMM', 'VNN', 'ESP'], # 'ESP' = transaction en espèces
'TRX_C_D': ['C', 'C', 'C'],
# Groupe 4: Informations sur les contreparties
# Pour les transactions en espèces (TRX_TYPE = 'ESP'), on mettra des NaN
'CP_PK': [432, 289, None],
'CP_RISK': [7, 5, None],
'CP_SCORE': [2345, 1243, None],
# Groupe 5: Agrégations
# Ici, TOTAL_CP et TOTAL_CASH représentent le total des transactions de contreparties ou en espèces
# par alert et party_key. Pour les transactions en espèces, TOTAL_CP prendra la valeur totalisée
# sur les autres transactions si c'est pertinent.
'NBR_CP_TRX': [2, 2, 2], # Ici, même en espèces, on peut comptabiliser le total si besoin
'NBR_CP': [2, 2, 2],
'TOTAL_CP': [250, 250, 250],
'TOTAL_CASH': [1000, 1000, 1000],
# Groupe 6: ISSUE (variable cible binaire)
'ISSUE': [1, 1, 1]
}
df = pd.DataFrame(data)
# 3. Préparation et nettoyage des données
# Conversion des colonnes de date en datetime
df['ALERT_DATE'] = pd.to_datetime(df['ALERT_DATE'])
df['TRX_DATE'] = pd.to_datetime(df['TRX_DATE'])
# Pour les transactions en espèces, s'assurer que les informations de contrepartie sont bien NaN
df.loc[df['TRX_TYPE'] == 'ESP', ['CP_PK', 'CP_RISK', 'CP_SCORE']] = np.nan
# Affichage des premières lignes pour vérification
print("Aperçu du DataFrame:")
print(df.head())
# 4. Analyse exploratoire (EDA)
# Statistiques descriptives globales
print("\nStatistiques descriptives globales:")
print(df.describe(include='all'))
# Statistiques par groupe (par exemple: par PARTY_POPULATION_GROUP)
print("\nStatistiques par groupe de 'PARTY_POPULATION_GROUP':")
print(df.groupby('PARTY_POPULATION_GROUP').describe())
# -----------------------
# Visualisations
# -----------------------
# 4.1 Histogramme pour PARTY_RISK
plt.figure(figsize=(6,4))
plt.hist(df['PARTY_RISK'], bins=range(1, 11), edgecolor='black')
plt.xlabel("Niveau de risque du party")
plt.ylabel("Fréquence")
plt.title("Distribution du PARTY_RISK")
plt.grid(True)
plt.show()
# 4.2 Histogramme pour CP_RISK (uniquement pour transactions avec contrepartie renseignée)
plt.figure(figsize=(6,4))
plt.hist(df['CP_RISK'].dropna(), bins=range(0, 11), edgecolor='black')
plt.xlabel("Niveau de risque de la contrepartie")
plt.ylabel("Fréquence")
plt.title("Distribution du CP_RISK")
plt.grid(True)
plt.show()
# 4.3 Boxplot de TRX_AMOUNT selon TRX_TYPE
plt.figure(figsize=(6,4))
types = df['TRX_TYPE'].unique()
data_box = [df.loc[df['TRX_TYPE'] == t, 'TRX_AMOUNT'] for t in types]
plt.boxplot(data_box, labels=types)
plt.xlabel("Type de transaction")
plt.ylabel("Montant de la transaction")
plt.title("Boxplot du TRX_AMOUNT par TRX_TYPE")
plt.grid(True)
plt.show()
# 4.4 Heatmap de corrélation entre les variables numériques
# Sélection des colonnes numériques pertinentes
numerical_cols = ['PARTY_RISK', 'TRX_AMOUNT', 'CP_RISK', 'CP_SCORE', 'NBR_CP_TRX', 'NBR_CP', 'TOTAL_CP', 'TOTAL_CASH', 'ISSUE']
corr = df[numerical_cols].corr()
plt.figure(figsize=(8,6))
plt.imshow(corr, cmap='viridis', interpolation='none', aspect='auto')
plt.colorbar()
plt.xticks(range(len(numerical_cols)), numerical_cols, rotation=45, ha='right')
plt.yticks(range(len(numerical_cols)), numerical_cols)
plt.title("Heatmap de corrélation entre variables numériques")
plt.tight_layout()
plt.show()
# 4.5 Scatter plot : TRX_AMOUNT vs. CP_SCORE (pour transactions avec CP_SCORE non-null)
plt.figure(figsize=(6,4))
mask = df['CP_SCORE'].notnull()
plt.scatter(df.loc[mask, 'TRX_AMOUNT'], df.loc[mask, 'CP_SCORE'], alpha=0.7)
plt.xlabel("TRX_AMOUNT")
plt.ylabel("CP_SCORE")
plt.title("Scatter plot: TRX_AMOUNT vs CP_SCORE")
plt.grid(True)
plt.show()
# -----------------------
# 5. Préparation pour le modèle prédictif
# -----------------------
# Pour la prédiction, nous utiliserons les variables jugées pertinentes.
# Ici, nous utilisons toutes les variables numériques et nous encodons la variable catégorielle PARTY_POPULATION_GROUP.
# Nous retirons les colonnes d'identifiants ou dates qui ne servent pas directement à la prédiction.
# On peut conserver : PARTY_RISK, TRX_AMOUNT, CP_RISK, CP_SCORE, NBR_CP_TRX, NBR_CP, TOTAL_CP, TOTAL_CASH
# Et on encode : PARTY_POPULATION_GROUP
# On peut aussi éventuellement calculer des features temporels (par exemple, délai entre ALERT_DATE et TRX_DATE) si pertinent.
# Calcul d'une nouvelle feature : délai (en jours) entre ALERT_DATE et TRX_DATE
df['DELAY_DAYS'] = (df['ALERT_DATE'] - df['TRX_DATE']).dt.days
# Sélection des features à utiliser pour le modèle
features = ['PARTY_RISK', 'TRX_AMOUNT', 'CP_RISK', 'CP_SCORE',
'NBR_CP_TRX', 'NBR_CP', 'TOTAL_CP', 'TOTAL_CASH', 'DELAY_DAYS', 'PARTY_POPULATION_GROUP']
target = 'ISSUE'
# Conserver uniquement les lignes nécessaires (si des données manquent, vous pouvez aussi choisir d'imputer)
df_model = df[features + [target]].copy()
# Traitement des valeurs manquantes : ici nous imputons par la médiane pour les variables numériques
for col in ['CP_RISK', 'CP_SCORE']:
df_model[col] = df_model[col].fillna(df_model[col].median())
# Encodage de la variable catégorielle PARTY_POPULATION_GROUP
# Nous utilisons OneHotEncoder pour transformer cette colonne.
# Nous allons construire un pipeline pour le prétraitement.
categorical_features = ['PARTY_POPULATION_GROUP']
numerical_features = [col for col in features if col not in categorical_features]
preprocessor = ColumnTransformer(
transformers=[
('num', StandardScaler(), numerical_features),
('cat', OneHotEncoder(drop='first'), categorical_features) # drop_first pour éviter la redondance
])
# Séparation des données en ensembles d'entraînement et de test (70% train, 30% test)
X = df_model[features]
y = df_model[target]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 6. Construction et évaluation des modèles
# 6.1 Pipeline pour la régression logistique
pipeline_lr = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', LogisticRegression(max_iter=1000, random_state=42))])
# Entraînement du modèle de régression logistique
pipeline_lr.fit(X_train, y_train)
# Prédictions
y_pred_lr = pipeline_lr.predict(X_test)
print("\n--- Régression Logistique ---")
print("Classification Report :")
print(classification_report(y_test, y_pred_lr))
# Validation croisée (par exemple 5-fold) sur l'ensemble d'entraînement
cv_scores_lr = cross_val_score(pipeline_lr, X_train, y_train, cv=5, scoring='accuracy')
print("Scores de validation croisée (Logistique):", cv_scores_lr)
print("Score moyen (Logistique): {:.2f}".format(cv_scores_lr.mean()))
# 6.2 Pipeline pour une forêt aléatoire
pipeline_rf = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', RandomForestClassifier(random_state=42))])
# Entraînement du modèle forêt aléatoire
pipeline_rf.fit(X_train, y_train)
# Prédictions
y_pred_rf = pipeline_rf.predict(X_test)
print("\n--- Forêt Aléatoire ---")
print("Classification Report :")
print(classification_report(y_test, y_pred_rf))
# Validation croisée sur la forêt aléatoire
cv_scores_rf = cross_val_score(pipeline_rf, X_train, y_train, cv=5, scoring='accuracy')
print("Scores de validation croisée (RF):", cv_scores_rf)
print("Score moyen (RF): {:.2f}".format(cv_scores_rf.mean()))
# 6.3 Matrice de confusion et courbe ROC (pour le modèle de régression logistique)
cm = confusion_matrix(y_test, y_pred_lr)
plt.figure(figsize=(4,4))
plt.imshow(cm, interpolation='nearest', cmap='Blues')
plt.title("Matrice de confusion - Régression Logistique")
plt.colorbar()
tick_marks = np.arange(2)
plt.xticks(tick_marks, ['0', '1'])
plt.yticks(tick_marks, ['0', '1'])
plt.xlabel("Prédiction")
plt.ylabel("Réalité")
for i in range(2):
for j in range(2):
plt.text(j, i, format(cm[i, j], 'd'),
horizontalalignment="center", color="red")
plt.tight_layout()
plt.show()
# Courbe ROC
y_prob_lr = pipeline_lr.predict_proba(X_test)[:, 1]
fpr, tpr, thresholds = roc_curve(y_test, y_prob_lr)
roc_auc = auc(fpr, tpr)
plt.figure(figsize=(6,4))
plt.plot(fpr, tpr, label="AUC = {:.2f}".format(roc_auc))
plt.plot([0, 1], [0, 1], linestyle='--')
plt.xlabel("Taux de faux positifs")
plt.ylabel("Taux de vrais positifs")
plt.title("Courbe ROC - Régression Logistique")
plt.legend(loc='lower right')
plt.grid(True)
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment