.. _td2aecocompetitionmodeleslogistiquesrst: =================================================== 2A.ml - 2016 - Compétition ENSAE - Premiers modèles =================================================== .. only:: html **Links:** :download:`notebook `, :downloadlink:`html `, :download:`python `, :downloadlink:`slides `, :githublink:`GitHub|_doc/notebooks/competitions/2016/td2a_eco_competition_modeles_logistiques.ipynb|*` Une compétition était proposée dans le cadre du cours *Python pour un Data Scientist* à l’\ `ENSAE `__. Ce notebook facilite la prise en main des données et propose de mettre en oeuvre un modèle logit. .. code:: ipython3 from jyquickhelper import add_notebook_menu add_notebook_menu() .. contents:: :local: La première étape constiste à mettre en forme les données pour que les fonctions des modules statsmodels et skitlearn fonctionnent comme on le souhaite .. code:: ipython3 from pyensae.datasource import download_data download_data("ensae_competition_2016.zip", url="https://github.com/sdpython/ensae_teaching_cs/raw/master/_doc/competitions/2016_ENSAE_2A/") .. parsed-literal:: ['ensae_competition_test_X.txt', 'ensae_competition_train.txt'] .. code:: ipython3 import pandas as pd import statsmodels.api as sm import pylab as pl import numpy as np fichier_train = "./ensae_competition_train.txt" fichier_test = "./ensae_competition_test_X.txt" df = pd.read_csv(fichier_train, header=[0,1], sep="\t", index_col=0) .. parsed-literal:: c:\python36_x64\lib\site-packages\statsmodels\compat\pandas.py:56: FutureWarning: The pandas.core.datetools module is deprecated and will be removed in a future version. Please use the pandas.tseries module instead. from pandas.core import datetools Mise en forme des données pour la régression -------------------------------------------- Pour mieux analyser les données présentes dans la base de données, il faut passer par quelques manipulations. Par exemple, il faut transformer les variables SEX, EDUCATION, MARRIAGE en indictatrices afin qu’elles ne soient pas prise en compte comme des variables continues dans le modèle. .. code:: ipython3 #### Gender dummies df['X2'] = df['X2'].applymap(str) gender_dummies = pd.get_dummies(df['X2'] ) .. code:: ipython3 ### education dummies df['X3'] = df['X3'].applymap(str) educ_dummies = pd.get_dummies(df['X3'] ) .. code:: ipython3 #### marriage dummies df['X4'] = df['X4'].applymap(str) mariage_dummies = pd.get_dummies(df['X4'] ) .. code:: ipython3 ### On va aussi supprimer les multi index de la table df.columns = df.columns.droplevel(0) .. code:: ipython3 #### on aggrège ensuite les 3 tables ensemble data = df.join(gender_dummies).join(educ_dummies).join(mariage_dummies) data.head(n=2) .. raw:: html
LIMIT_BAL SEX EDUCATION MARRIAGE AGE PAY_0 PAY_2 PAY_3 PAY_4 PAY_5 ... EDUCATION_1 EDUCATION_2 EDUCATION_3 EDUCATION_4 EDUCATION_5 EDUCATION_6 MARRIAGE_0 MARRIAGE_1 MARRIAGE_2 MARRIAGE_3
0 180000 1 2 1 47 0 0 0 0 0 ... 0 1 0 0 0 0 0 1 0 0
1 110000 2 2 1 35 0 0 0 0 0 ... 0 1 0 0 0 0 0 1 0 0

2 rows × 37 columns

Régression logistique en utilisant statsmodels ---------------------------------------------- Pour notre premier modèle, nous allons voir comment fonctionne le module statsmodels Par défaut, la regression logit n’a pas de beta zéro pour le module statsmodels : il faut donc l’ajouter .. code:: ipython3 # première étape pour ce module, il faut ajouter à la main le beta zéro - l'intercept data['intercept'] = 1.0 data.rename(columns = {'default payment next month' : "Y"}, inplace = True) data.columns .. parsed-literal:: Index(['LIMIT_BAL', 'SEX', 'EDUCATION', 'MARRIAGE', 'AGE', 'PAY_0', 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6', 'BILL_AMT1', 'BILL_AMT2', 'BILL_AMT3', 'BILL_AMT4', 'BILL_AMT5', 'BILL_AMT6', 'PAY_AMT1', 'PAY_AMT2', 'PAY_AMT3', 'PAY_AMT4', 'PAY_AMT5', 'PAY_AMT6', 'Y', 'SEX_1', 'SEX_2', 'EDUCATION_0', 'EDUCATION_1', 'EDUCATION_2', 'EDUCATION_3', 'EDUCATION_4', 'EDUCATION_5', 'EDUCATION_6', 'MARRIAGE_0', 'MARRIAGE_1', 'MARRIAGE_2', 'MARRIAGE_3', 'intercept'], dtype='object') .. code:: ipython3 # variable = ['AGE', 'BILL_AMT1', 'BILL_AMT2', 'BILL_AMT3', 'BILL_AMT4', # 'BILL_AMT5', 'BILL_AMT6', 'LIMIT_BAL', 'PAY_0', # 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6', 'PAY_AMT1', 'PAY_AMT2', # 'PAY_AMT3', 'PAY_AMT4', 'PAY_AMT5', 'PAY_AMT6', 'SEX_1', # 'EDUCATION_0', 'EDUCATION_1', 'EDUCATION_2', 'EDUCATION_3', # 'EDUCATION_4', 'EDUCATION_5', 'MARRIAGE_0', 'MARRIAGE_1', # 'MARRIAGE_2', 'intercept'] train_cols = ["SEX_1", "AGE", "MARRIAGE_0", 'PAY_0','intercept'] .. code:: ipython3 # Cette cellule n'est nécessaire que si vous utilisez scipy 1.0 avec statsmodels 0.8. from pymyinstall.fix import fix_scipy10_for_statsmodels08 fix_scipy10_for_statsmodels08() .. code:: ipython3 logit = sm.Logit(data['Y'], data[train_cols].astype(float)) # fit the model result = logit.fit() print(result.summary()) .. parsed-literal:: Optimization terminated successfully. Current function value: 0.475306 Iterations 6 Logit Regression Results ============================================================================== Dep. Variable: Y No. Observations: 22500 Model: Logit Df Residuals: 22495 Method: MLE Df Model: 4 Date: Wed, 01 Nov 2017 Pseudo R-squ.: 0.1008 Time: 20:48:54 Log-Likelihood: -10694. converged: True LL-Null: -11893. LLR p-value: 0.000 ============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ SEX_1 0.1093 0.035 3.144 0.002 0.041 0.177 AGE 0.0076 0.002 4.202 0.000 0.004 0.011 MARRIAGE_0 -0.8095 0.527 -1.536 0.124 -1.842 0.223 PAY_0 0.7304 0.016 44.554 0.000 0.698 0.763 intercept -1.7150 0.067 -25.435 0.000 -1.847 -1.583 ============================================================================== Prédiction sur la base de test ------------------------------ On va prédire les probabilités de défaut de paiement sur notre base de test. Il faut commencer par transformer la base de test comme on l’a fait pour la base de train. .. code:: ipython3 data_test = pd.read_csv(fichier_test, header=[0,1], sep="\t", index_col=0) .. code:: ipython3 #### Gender dummies data_test['X2'] = data_test['X2'].applymap(str) gender_dummies_test = pd.get_dummies(data_test['X2'] ) .. code:: ipython3 ### education dummies data_test['X3'] = data_test['X3'].applymap(str) educ_dummies_test = pd.get_dummies(data_test['X3'] ) .. code:: ipython3 #### marriage dummies data_test['X4'] = data_test['X4'].applymap(str) mariage_dummies_test = pd.get_dummies(data_test['X4'] ) .. code:: ipython3 ### On va aussi supprimer les multi index de la table data_test.columns = data_test.columns.droplevel(0) .. code:: ipython3 #### on aggrège ensuite les 3 tables ensemble data_test = data_test.join(gender_dummies_test).join(educ_dummies_test).join(mariage_dummies_test) .. code:: ipython3 data_test['intercept'] = 1.0 .. code:: ipython3 data_test[train_cols].head() .. raw:: html
SEX_1 AGE MARRIAGE_0 PAY_0 intercept
0 0 35 0 0 1.0
1 0 55 0 -1 1.0
2 1 33 0 0 1.0
3 1 23 0 0 1.0
4 1 42 0 -2 1.0
Maintenant que la base de test est également transformée, nous allons appliqué les résultats de notre modèle à cette table en utilisant la fonction predict .. code:: ipython3 data_test['prediction_statsmodel'] = result.predict(data_test[train_cols]) data_test['prediction_statsmodel'].describe() .. parsed-literal:: count 7500.000000 mean 0.220305 std 0.136834 min 0.025511 25% 0.114870 50% 0.194184 75% 0.225708 max 0.988777 Name: prediction_statsmodel, dtype: float64 On trouve un taux moyen de défaut de 22%, ce qui est très proche du taux observé dans la base de train .. code:: ipython3 # puis on l'exporte data_test['prediction_statsmodel'].to_csv("./answer.csv", index=False) Regression logistique en utilisant Scikit-learn ----------------------------------------------- A présent, nous allons utiliser le module scikit learn pour estimer le même modèle que précédemment et comparer les résultats. Ici pas besoin d’ajouter une variable égale à 1 (l’intercept) car Scikit learn considère qu’il y a un intercept par défaut. .. code:: ipython3 from sklearn import linear_model logistic = linear_model.LogisticRegression() .. code:: ipython3 print("l'estimation des coefficients", logistic.fit(data[train_cols], data['Y']).coef_, "\n") print("l'intercept : ", logistic.fit(data[train_cols], data['Y']).intercept_) .. parsed-literal:: l'estimation des coefficients [[ 0.10899192 0.00751036 -0.56310513 0.72994068 -0.85555264]] l'intercept : [-0.85555264] A la différence de statsmodels, Scikit-learn ne propose pas une belle table de résultat : seulement les arrays qui contiennent les coefficients Pour le détail des p-value et intervalles de confiance, il faudra les recalculer à la main. Par contre, la fonction de prédiction existe et elle renvoit la probabilité de Y = 0 et Y = 1 .. code:: ipython3 logistic.predict_proba(data_test[train_cols]) .. parsed-literal:: array([[ 0.80972784, 0.19027216], [ 0.88370325, 0.11629675], [ 0.79482709, 0.20517291], ..., [ 0.80972784, 0.19027216], [ 0.88899819, 0.11100181], [ 0.79667299, 0.20332701]]) .. code:: ipython3 # pour calculer la moyenne du taux de défaut prédit logistic.predict_proba(data_test[train_cols]).mean(axis=0) # on trouve à nouveau 22% .. parsed-literal:: array([ 0.77965411, 0.22034589])