Comparaison de modèles, apprentissage des LPC et vraisemblance
Table des matières
Figure 1 : Dall-E 3: machine learning digital marketing bank loan ; white background ; colorful
1. Objectif
L'objectif de cet exercice est de comparer l'influence du choix de la structure d'un RB sur la représentativité de données observées. Autrement dit, il s'agit d'un problème de sélection de modèles.
Pour ce faire, nous nous intéresserons à des données de retour marketing (fictives) sur la vente de livret A. Dans ces données, les individus sont décrits par les variables suivantes :
- Age :
- classe d'âges de l'individu - valeurs possibles : [18,25], [26,59], 60+;
- Epargne :
- l'individu a t-il de l'épargne - valeurs possibles : non, oui;
- Vente_livret_A :
- vente d'un livret A à l'individu - valeurs possibles : échec, succès.
Une des applications classiques de ce type de modèles est le ciblage client. Pour un produit donné, l'idée est de trouver les caractéristiques de la population qui maximisent les chances de vente.
2. Apprentissage avec pyAGRuM
2.1. Modèle 1 : \(A \rightarrow V \leftarrow E\)
Importez le module
pyagrumdans votre environnementPython.import pyAgrum as gum # La librairie pyAgrum # Vérification des versions { "pyagrum": gum.__version__, }
pyagrum : 1.12.1 Construire la structure du modèle 1.
# Création du RB bn1 = gum.BayesNet("Vente livret") # Création de la variable Vente va_V = gum.LabelizedVariable("Vente_livret_A", "Vente livret", 2) va_V.changeLabel(0, "echec") va_V.changeLabel(1, "succes") # Création de la variable Âge va_A = gum.LabelizedVariable("Age", "Âge", 3) va_A.changeLabel(0, "c18_25") va_A.changeLabel(1, "c26_59") va_A.changeLabel(2, "c60") # Création de la variable Épargne va_E = gum.LabelizedVariable("Epargne", "Épargne", 2) va_E.changeLabel(0, "non") va_E.changeLabel(1, "oui") # TODO : ajout des variable dans le RB (méthode .add) # TODO : ajout des arcs (méthode .addArc)
# SOLUTION # -------- # Ajout des variables dans le RB bn1.add(va_V) bn1.add(va_A) bn1.add(va_E) # Ajout des arcs bn1.addArc("Age", "Vente_livret_A") bn1.addArc("Epargne", "Vente_livret_A")
Téléchargez le fichier de données vente_livret_A_donnees_10000.csv et lisez ces données dans un
DataFramePandasavec la fonctionread_csv.# Lecture des données import pandas as pd data_df = pd.read_csv("vente_livret_A_donnees_10000.csv")
Utilisez la classe
gum.BNLearneret en particulier la méthodefitParameterspour réaliser l'apprentissage des LPC de votre modèle.learner = gum.BNLearner(data_df) learner.fitParameters(bn1) print(bn1.cpt("Vente_livret_A")) print(bn1.cpt("Age")) print(bn1.cpt("Epargne"))
Créez une fonction
loglikelihoodprenant en entrées un RB et unDataFramereprésentant les mêmes variables et retournant la vraisemblance du RB par rapport au données. Il vous faudra utiliser un moteur d'inférence (ex:gum.LazyPropagation) et ses méthodes.setEvidenceet.evidenceProbability.import math # Pour utiliser math.log def loglikelihood(bn, data_df): # TODO: Code à écrire ;) return loglike
# SOLUTION # -------- import math # Pour utiliser math.log def loglikelihood(bn, data_df): loglike = 0 # Création d'un moteur d'inférence inf_engine = gum.LazyPropagation(bn) for idx, obs in data_df.iterrows(): # Projection de la données courante dans le RB inf_engine.setEvidence(obs.to_dict()) # Calcul de la probabilité (vraisemblance) de la données dans le RB data_loglike = inf_engine.evidenceProbability() # Passage au log pour obtenir la log-vraisemblance de la données # et somme pour calculer la vraisemblance sur toutes les données loglike += math.log(data_loglike) return loglike
Utilisez votre fonction pour calculer la vraisemble du modèle 1 par rapport aux données.
loglike = loglikelihood(bn1, data_df) print(loglike)
-22879.905249672032
2.2. Autres modèles
Reprendre les étapes précédentes sur les modèles suivants :
- Modèle 2 : \(A \leftarrow V \rightarrow E\).
- Modèle 3 : \(A \leftarrow V \rightarrow E\) et \(A \rightarrow E\).
- Modèle 4 : \(A \leftarrow V \rightarrow E\) et \(A \leftarrow E\).
- Modèle 5 : \(A\), \(V\), \(E\) indépendantes.
Comparer les log-vraisemblance obtenues et expliquer les résultats.
# SOLUTION # -------- # Spécification des structures de chaque modèle bn_struct_specs = { "M1": [("Age", "Vente_livret_A"), ("Epargne", "Vente_livret_A")], "M2": [("Vente_livret_A", "Age"), ("Vente_livret_A", "Epargne")], "M3": [("Vente_livret_A", "Age"), ("Vente_livret_A", "Epargne"), ("Age", "Epargne")], "M4": [("Vente_livret_A", "Age"), ("Vente_livret_A", "Epargne"), ("Epargne", "Age")], "M5": [], } # Boucle de construction de chaque modèle bn_models = {} for bn_name, struct in bn_struct_specs.items(): # Construction du RB courant bn = gum.BayesNet(bn_name) bn.add(va_V) bn.add(va_A) bn.add(va_E) [bn.addArc(*arc) for arc in struct] # Apprentissage des LPC learner.fitParameters(bn) bn_models[bn_name] = bn # Boucle de calcul des vraisemblances de chaque modèle bn_loglike = {} for bn_name, bn in bn_models.items(): bn_loglike[bn_name] = loglikelihood(bn, data_df) print(bn_loglike)
{'M1': -22879.905249672032, 'M2': -23296.642978057353, 'M3': -21958.960794571823, 'M4': -21958.960794571823, 'M5': -24196.13497634752}
3. Évaluation des modèles avec pyAGRuM
L'objectif est à présent de tester les performances de nos modèles pour effectuer des ciblages de clientèle. Les clients à cibler se trouvent dans le fichier vente_livret_A_donnees_100_test.csv contenant ce que nous appellerons dans la suite les données de test. Ces données contiennent à la fois les caractéristiques des clients à cibler (âge, épargne) mais aussi le résultat réel de la vente. La performance d'un modèle correspondra donc au taux de bonnes prédictions du modèle sur l'issue des ventes.
Pour ce faire, vous pouvez utiliser la fonction predict suivante permettant de calculer les
probabilités a posteriori d'une variable à partir de l'observation d'autres variables.
import numpy as np import sys def predict(bn, data, var_target, show_progress=False): """ This function is used to predict the posterior probability of a target variable from observations using a bayesian network model. Inputs: - =bn=: the predictive model given as a =pyAgrum.BayesNet= object - =data=: the data containing the observations used to predict the target variable as a =pandas.DataFrame= object - =var_target=: the name of the target variable as a =str= object Returns: - a =DataFrame= containing the posterior probability distribution of the target variable given each observation in =data=. """ # Initialize the inference engine inf_bn = gum.LazyPropagation(bn) inf_bn.setTargets({var_target}) nb_data = len(data) target_size = bn.variable(var_target).domainSize() target_dom = np.array([bn.variable(var_target).label(i) for i in range(target_size)]) data_records = data.to_dict("records") post_prob = np.zeros((nb_data, target_size)) for i in range(nb_data): # Set the evidence inf_bn.setEvidence(data_records[i]) # Run inference inf_bn.makeInference() # Compute posterior probability of target variable post_prob[i, :] = inf_bn.posterior(var_target).toarray() # Erase evidence inf_bn.eraseAllEvidence() if show_progress: sys.stdout.write("predict progress: {0:3.0%}\r".format(i/nb_data)) post_prob_df = pd.DataFrame(post_prob, index=data.index, columns=bn.variable(var_target).labels()) post_prob_df.columns.name = var_target return post_prob_df
Réaliser les étapes suivantes pour chacun des modèles construits à la phase précédente :
Chargez le fichier de données de test vente_livret_A_donnees_100_test.csv dans un
DataFramenommédata_test_df.# SOLUTION # -------- data_test_df = pd.read_csv("vente_livret_A_donnees_100_test.csv")
Utilisez la fonction
predictavec le modèle 1 de manière à prédire les loisa posterioride la variableVente_livret_Aconditionnellement à chaque observation des variablesAgeetEpargnedans les données de test.m1_prob_test = predict(bn1, data=data_test_df[["Age", "Epargne"]], var_target="Vente_livret_A")
Calculez, pour chaque prédiction, la modalité (
echecousucces) qui maximise la probabilité a posteriori.m1_pred_test = m1_prob_test.idxmax(axis=1)Calculez le taux de bonnes prédictions du modèle 1 sur les données de test.
# SOLUTION # -------- m1_accuracy_test = (data_test_df["Vente_livret_A"] == m1_pred_test).mean()
- Comparer les performances observées de ce chaque modèle et expliquer les résultats.
# SOLUTION # -------- # Boucle de calcul des prédictions et des performances bn_accuracy = {} for bn_name, bn in bn_models.items(): prob_test = predict(bn, data=data_test_df[["Age", "Epargne"]], var_target="Vente_livret_A") pred_test = prob_test.idxmax(axis=1) accuracy_test = (data_test_df["Vente_livret_A"] == pred_test).mean() bn_accuracy[bn_name] = accuracy_test print(bn_accuracy)
{'M1': 0.74, 'M2': 0.67, 'M3': 0.74, 'M4': 0.74, 'M5': 0.53}