Après avoir réalisé le premier objectif de segmentation ou profilage des types de comportement des français vis à vis de leur patrimoine, l'objectif, est de contruire un outil classique en GRr (gestion de la relation client). La plupart des méthodes sont abordées et comparées régression logistique, analyse discriminante, arbre de discrimination, agrégation de modèles, SVM. Les estimations des erreurs de prévision et les courbes ROC sont comparées à la suite du tirage itératif d'un ensemble d'échantillons tests.
Le travail proposé vient compléter le cours sur l'apprentissage statistique. Son objectif est double :
Il s'intéresse à un jeu de données décrivant le patrimoine des français (enquête INSEE) et se propose de comparer plusieurs méthodes de modélisation (régression logistique, réseaux de neurones, arbres de décision, agrégation de modèles) pour aborder un problème très classique en Gestion de la Relation Client (GRC / CRM) : construire un score d'appétence. Il s'agit du score d'appétence pour l'assurance vie mais ce pourrait être un score d'attrition (churn) d'un opérateur téléphonique ou encore un score de défaillance d'un emprunteur ou de faillite d'une entreprise ; les outils de modélisation sont les mêmes et sont très largement utilisés dans tout le secteur tertiaire pour l'aide à la décision.
Les données sont publiques et accessibles sur le site de l'INSEE. Elles sont issues d'une enquête "Patrimoine" réalisée en 2003-2004 qui faisait suite à des enquêtes "Actifs financiers" de 1986 et 1992. L'enquête Patrimoine visait une connaissance globale du patrimoine des ménages ainsi que de ses principales composantes. Elle recense tous les différents types d'actifs financiers, immobiliers et professionnels détenus par les individus ainsi que les différents types d'emprunts (immobilier, à la consommation, achat voiture, biens professionnels, ...). Outre la connaissance de souscriptions à différents types de produits, l'enquête interroge aussi les individus sur leur motivation de détention permettant ainsi d'appréhender le comportement patrimonial des ménages.
Attention: La structure des données est relativement complexe, il est vivement recommandé d'avoir réalisé le scénario précédent d'exploration des données, où elles sont précisément décrites, avant de se lancer dans le travail de modélisation qui va suivre.
Finalement, à l'issue ce travail préliminaire et d'exploration, l'étude présente débute avec une base contenant 11887 individus décrits par 36 variables dont 2 sont redondantes (qualitatives et quantitatives) :
Age, Nbenf
Asvi, Sexe, Tage, Couple, Vmatri, Diplome, Ocupa, Work, statut, Herit, Pere, Mere, Gparp, gparm, Jgrav, Livep, Epalo, fepsal, vmob, livdf, pel, cel, qpep, asdecv, Retrai, Qpea, Urbani, Zeat, Nbenfq, Iogoc, terre, dette, bdetre, hdetvo
définies dans le Tableau ci-dessous.
Une première conclusion de l'étude précédente montre qu'il aurait été sûrement beaucoup plus efficace, à même coût, d'interroger beaucoup moins de monde avec beaucoup moins de questions mais en prenant le temps d'obtenir des réponses précises à l'ensemble des questions ! C'est malheureusement un comportement excessivement répandu dans beaucoup de disciplines, des Sciences humaines à la Biologie, de viser un niveau de détail beaucoup trop fin au regard de la précision des données ou de la taille de l'échantillon. Ainsi, les variables décrivant les ressources et le patrimoine n'ont même pas été prises en compte car elles présentent beaucoup trop de données manquantes : 90 \% pour le patrimoine financier, 60 \% pour l'autre ; même chose pour les variables relatives aux petits enfants. C'est la faiblesse majeure de cette enquête ; trop d'informations tue l'information.
L'absence de ces variables va pénaliser sévèrement la qualité des modèles mais c'est une réalité à laquelle il est nécessaire de se confronter.
Tableau: Identifiant, signification des variables retenues et liste des modalités; les identifiants des variables et modalités ont été choisis courts et mnémotechniques pour simplifier et aider l'interprétation des graphiques.
Identif. | Libellé | Modalités |
---|---|---|
Asvi | Possession ou non assurance vie | AsO, AsN |
AsviR | idem | 1, 0 |
Sexe | Genre | Sh, Sf |
Age | Age | Quantitatif |
Tage | Tranches d'âge | T10 à T90 |
Couple | Vie ou non en couple | CouO CouN |
Vmatri | Statut matrimonial | Vcel Vmar Vveu Vdiv |
Nation | Nationalité | Nfra Nnat Netr |
Diplome | Niveau de diplôme | Dsan, Dcep, Dtec (cap, bep), Dbepc, Dbact Dbacg, Db+2, Db+5 |
Occupa | Type d'occupation | Oact, Oina (foyer, chom, other), Oret |
Work | Niveau professionnel | WctA (cadre, catA), WctB (agent, catB, tech), Wemp, WctC (osp, ouv) |
statut | Statut professionnel | spri, spub, sind |
Herit | Bénéfice ou non d'un héritage | HerO, HerN |
Pere | Présence ou non du père | PerO PerN PerI |
Mere | Présence ou non de la mère | MerO, MerN MerI |
Gparp | Grands parents paternels | GppO GppN GppI |
gparm | Grands parents maternels | gpmO gpmN gpmI |
Jgrav | Evènement grave dans la jeunesse | JgvO JgvN |
Livep | Livret d'épargne | LivO LivN |
Epalo | Epargne logement | EplO EplN |
qpep | Plan d'épargne populaire | qppO qppN |
vmob | Valeurs mobilières | vmoO vmoN |
asdecv | Assurance décès volontaire | asdO asdN |
Retrait | Epargne retraite | RepO RepN |
livdf | Livret défiscalisé | ldfO, ldfN |
pel | Plan épargne logement | pelO, pelN |
cel | Compte épargne logement | celO, celN |
xcapi | Bons de capitalisation | xcpO xcpN |
fepsal | Epargne salarial ou stock options | fesO fesN |
Qpea | Plan épargne action | QpeO QpeN |
Urbani | Niveau d'urbanisation | U1 à U5 |
Zeat | Région de résidence | Zso Zpar Zoue Zne Zmed Zidf Zcen |
Nbenf | Nombre d'enfants | Quantitatif |
Nbenfq | Nombre d'enfants | Nbe0, Nbe1, Nbe2, Nb>3 |
Iogoc | Type d'occupation du logement | Iloc, Iprp (usufruit) |
terre | Possession de terres | terO terN |
dette | Dettes ou emprunts | detO detN |
bdetre | Emprunt achat maison | bemO bemN |
hdetvo | Emprunt voiture | hevO hevN |
Répondre aux questions en s'aidant des résultats des exécutions.
L'objectif est la recherche d'un meilleur modèle de prévision de la probabilité de possession d'un contrat d'assurance vie. Meilleur au sens de la minimisation d'une erreur de prévision estimée sur une partie tes de l'échantillon.
La démarche mise en \oe uvre enchaîne les étapes classiques suivantes :
Attention ne pas "tricher" en modifiant le modèle obtenu lors de l'étape précédente afin d'améliorer le résultat sur l'échantillon test !
Deux stratégies ou approches sont mises en \oe uvre :
caret
; la qualité de prévision prévaut.Celles-ci sont dans un fichier chargé en même temps que ce calepin.
In [ ]:
insee = read.csv("patriminsee.csv")
insee=insee[,-c(2,38)]
summary(insee)
Il s'agit d'isoler un échantillon test qui ne servira qu'à la seule comparaison des méthodes mais pas à l'estimation ni au choix de modèle inhérent à chacune d'elles. La séparation entre échantillon d'apprentissage et échantillon test se fait de la façon ci-dessous après initialisation du générateur de nombres aléatoires afin d'en contrôler la séquence pour d'autres exécutions. Il est vivement recommandé de conserver dans un fichier la liste des commandes R exécutées. Cela permettra ainsi de les ré-exécuter facilement pour une autre valeur de l'initialisation du générateur de nombres aléatoires.
In [ ]:
xxx=... # Initialiser xxx par un entier de votre choix
set.seed(xxx)
npop=nrow(insee)
# tirage de 3000 indices sans remise
testi=sample(1:npop,3000)
#Liste des indices restant qui n'ont pas été tirés
appri=setdiff(1:npop,testi)
# Extraction échantillon d'apprentissage
inseeAppt=insee[appri,]
# Extraction échantillon de test
inseeTest=insee[testi,]
summary(inseeAppt) # vérifications
In [ ]:
summary(inseeTest)
La régression logistique est une adaptation du modèle linéaire en vue de la prédiction d'une variable (binomiale) à deux modalités correspondant bien à l'objectif recherché.
Attention, les instructions ci-dessous sont données à titre indicatif; en effet, comme chaque groupe dispose d'un échantillon, dépendant de xxx
, différent, les sélections et listes de variables doivent être adaptées à la situation rencontrée.
La régression logistique est estimée dans R un considérant un cas particulier de modèle linéaire général (fonction glm
) de densité binomiale et de fonction lien la fonction lien canonique (logistique).
In [ ]:
# Estimation du modèle complet sans interaction
res.logit=glm(Asvi~.,data=inseeAppt,family=binomial)
# tests de nullité des coefficients
anova(res.logit,test="Chisq")
Q Commentaires sur les p-valeurs.
Une sélection de variables s'impose en utilisant une procédure automatique. Compte tenu du nombre raisonnable de variables, plusieurs stratégies peuvent être envisagées par minimisation du critère d'Akaïke (AIC). Noter bien que le critère utilisé par cette fonction de R est plus prédictif qu'explicatif.
Voici celle descendante :
In [ ]:
res.logit=glm(Asvi~.,data=inseeAppt,family=binomial)
res.step=step(res.logit,trace=0)
# variables du modèles
anova(res.step,test="Chisq")
Celle pas à pas :
In [ ]:
res2.logit=glm(Asvi~1,data=inseeAppt,family=binomial)
res2.step=step(res2.logit,direction="both",
scope=list(lower=~1, upper=~Sexe+Age+Tage+Couple+
Vmatri+Diplome+Occupa+Work+statut+Herit+Pere+Mere+
Gparp+gparm+Jgrav+Livep+Epalo+fepsal+vmob+livdf+
pel+cel+qpep+asdecv+Retrait+Qpea+Urbani+Zeat+
Nbenf+Nbenfq+Iogoc+terre+dette+bdetre+hdetvo),trace=0)
# observer les p-values
anova(res2.step,test="Chisq")
Comparer les deux modèles.
On peut par ailleurs se poser la question de la nécessité ou non de prendre en compte des interactions dans la démarche pas à pas ci-dessous.
In [ ]:
res3.logit=glm(Asvi~1,data=inseeAppt,family=binomial)
res3.step=step(res3.logit,direction="both",
scope=list(lower=~1,upper=~(Sexe+Tage+Work+Herit+
Epalo+fepsal+vmob+livdf+pel+cel+qpep+Retrait+Qpea+
Urbani+Zeat+Nbenfq+Iogoc+bdetre)**2), trace=0)
# observer les p-values
anova(res2.step,test="Chisq")
Rappel Chaque groupe dispose d'un échantillon d'apprentissage différent dépendant de l'initialisation du générateur. Les "meilleurs" modèles peuvent donc différer d'un groupe à l'autre et par rapport à ce qui est présenté dans ce texte.
Les modèles obtenus peuvent différer et certaines variables présenter des p-valeurs non significatives. Le modèle proposé par minimisation du critère AIC est peut-être trop complexe. Il s'agit donc de comparer les valeurs prédictives de ces modèles ou de sous modèles par validation croisée en retirant les variables les moins significatives une à une. La bibliothèque boot
propose une procédure de validation croisée adaptée à la fonction glm
.
In [ ]:
library(boot)
# premier modele
res.logit=glm(Asvi~Sexe+Tage+ Work+Herit+fepsal+vmob+
livdf+pel+cel+qpep+Retrait+Qpea+Urbani+Zeat+Nbenfq+
Iogoc+bdetre,data=inseeAppt,family=binomial)
cv.glm(inseeAppt,res.logit,K=10)$delta[1]
In [ ]:
# deuxieme modele
res2.logit=glm(Asvi ~ vmob+Tage+Epalo+Work+livdf+
Herit+qpep+bdetre+Iogoc+Nbenfq+fepsal+Sexe+Qpea+
Zeat+Urbani+Retrait+pel,data=inseeAppt,
family=binomial)
cv.glm(inseeAppt,res2.logit,K=10)$delta[1]
In [ ]:
# troisième modele avec interactions
res3.logit=glm(Asvi ~ vmob+Tage+Epalo+Work+livdf+
Herit+qpep+bdetre+Iogoc+fepsal+Nbenfq+Sexe+
Qpea+Zeat+Urbani+Retrait+pel+cel+vmob:Tage+
Tage:Iogoc+Work:Iogoc+Work:Herit+qpep:Qpea+
vmob:Epalo+livdf:Nbenfq+livdf:Urbani+
qpep:Iogoc+vmob:fepsal+bdetre:pel+Nbenfq:pel+
Zeat:pel+Tage:cel+Sexe:Urbani+bdetre:Sexe+
bdetre:fepsal+Nbenfq:Retrait,data=inseeAppt,
family=binomial)
cv.glm(inseeAppt,res3.logit,K=10)$delta[1]
Retenir le meilleur modèle.
In [ ]:
pred.logit=predict(res3.logit,newdata=inseeTest)>0.5
table(pred.logit,inseeTest$Asvi=="AsO")
Q Commentaires sur cette matrice de confusion.
Noter le taux d'erreur et sans doute le grand optimisme de la validation croisée.
Le tracer de cette courbe fait varier le seuil de la probabilité pour évaluer comment se comporte les caractéristiques de sensibilité et spécificité du modèle.
In [ ]:
library(ROCR)
roclogit=predict(res2.logit, newdata=inseeTest,type="response")
predlogistic=prediction(roclogit,inseeTest$Asvi)
perflogistic=performance(predlogistic, "tpr","fpr")
options(repr.plot.width=4, repr.plot.height=4)
plot(perflogistic,col=1)
Q Que penser de la qualité de ce modèle?
Cette section a pour objectif la construction d'un arbre de discrimination (classification tree) et son élagage par validation croisée pour optimiser sa capacité de discrimination.
Deux librairies tree
et rpart
et bien d'autres, proposent les techniques CART avec des algorithmes analogues à ceux développés dans Splus mais moins de fonctionnalités; rpart
fournissant des graphes plus explicites et une procédure d'élagage plus performante est préférée.
La première estimation favorise un arbre très détaillé c'est-à-dire avec un très faible coefficient de pénalisation de la complexité de l'arbre et donc du nombre de feuilles. Le critère d'hétérogénéité est l'entropie.
In [ ]:
library(rpart) # Chargement de la librairie
res.tree=rpart(Asvi~.,data=inseeAppt, parms=list(split='information'),cp=0.001)
# summary(res.tree) # Quelques renseignements (trop)
options(repr.plot.width=8, repr.plot.height=8)
plot(res.tree) # Tracé de l'arbre
text(res.tree) # Ajout des légendes des noeuds
Il est évident que l'arbre présente trop de feuilles. Une première façon de l'élaguer consiste à tracer la décroissance de l'erreur relative en fonction du coefficient de complexité c'est-à-dire aussi en fonction de la taille de l'arbre ou nombre de feuilles. La procédure est mal explicitée dans la documentation.
In [ ]:
options(repr.plot.width=8, repr.plot.height=4)
plotcp(res.tree)
Il faut alors choisir une valeur du coefficient de pénalisation de la complexité pour élaguer l'arbre. Attention, ce choix dépend de l'échantillon tiré. Il peut être différent de celui ci-dessous. La valeur de cp choisie correspond à la première valeur d''erreur relative'' sous les pointillés.
In [ ]:
library(partykit)
res2.tree=prune(res.tree,cp=0.0069)
options(repr.plot.width=4, repr.plot.height=4)
plot(as.party(res2.tree),gp = gpar(fontsize = 11))
In [ ]:
res.tree=rpart(Asvi~.,data=inseeAppt,parms=list(split='information'),
control = rpart.control(cp = .001))
xmat = xpred.rpart(res.tree,xval=10)
# Comparaison de la valeur prédite
# avec la valeur observée.
xerr=as.integer(inseeAppt$Asvi)!= xmat
# Calcul et affichage des estimations
# des taux d'erreur
apply(xerr, 2, sum)/nrow(xerr)
Q Comparer les choix de pénalisation.
In [ ]:
# Elagage puis affichage de l'arbre
res3.tree=prune(res.tree,cp=0.001816418)
options(repr.plot.width=8, repr.plot.height=8)
plot(as.party(res3.tree),gp = gpar(fontsize = 11))
Q Interpréter, ou non, les arbres. Que dire du choix des variables comparativement aux autres méthodes ?
Les commandes ci-dessous calculent la prévision de la variable Asvi
pour l'échantillon test et croisent la variable prédite avec la variable observée afin de construire les matrices de confusion et donc d'estimer les taux d'erreur.
In [ ]:
pred.tree=predict(res3.tree, newdata=inseeTest,type="class")
table(pred.tree,inseeTest$Asvi)
Q Noter et comparer les taux d'erreur ainsi que les courbes ROC :
In [ ]:
ROCrpart=predict(res3.tree,newdata=inseeTest,type="prob")[,2]
predrpart=prediction(ROCrpart,inseeTest$Asvi)
perfrpart=performance(predrpart,"tpr","fpr")
# tracer les courbes ROC
options(repr.plot.width=4, repr.plot.height=4)
plot(perflogistic,col=1)
# en les superposant pour mieux comparer
plot(perfrpart,col=2,add=TRUE)
Q Quelle meilleure méthode entre la régression logistique et un arbre de décision?
L'étude se limite à une utilisation de la librairie caret
(Kunh, 2008) pour quelques unes des méthodes de modélisation proposées. C'est un "méta-package" qui englobe dans une seule fonction train
l'appel des différentes fonctions d'estimation d'autre packages. La commande library
est incluse mais évidemment les packages utilisés doivent avoir été chargés.
Par ailleurs, même sous windows, caret
offre simplement des possibilités de parallèlisation en utilisant la package doParallel
. Même si les algorithmes des différentes méthodes d'apprentissage ne sont pas parallélisés, les itérations des calculs de validations croiser pour l'optimisation des paramètres sont effectivement parallélisés avec un gain de temps très appréciable fonciton du nombre de processeurs. Ceci est obtenu en exécutant les commandes suivantes en supposant que 4 processeurs sont disponibles.
In [ ]:
library(doParallel)
cl <- makeCluster(4)
registerDoParallel(cl)
Extraction des échantillons d'apprentissage et de test. Attention, le mode d'utilisation ou d'appel de la principale fonction : train
de caret
dépend du type des variables explicatives et de la méthode utilisée; c'est une limitation de l'aspect "généralisation" de ce méta-package. Pas de problème lorsque les variables $X^j$ sont toutes quantitatives mais des traitements différents des variables $X^j$ qualitatives. Les facteurs sont, ou non, transformés en dummy variables c'est-à-dire en indicatrices: une par modalité pour certaines méthodes. Ce n'est pas une procédure "optimale" en sélection de variables au moment de l'interprétation!
Dans le premier cas, tout quantitatif, il faut séparer les variables X de la variable cible à expliquer Y. Dans le 2ème, variables qualitatives, et pour certaines méthodes, il faut utiliser la syntaxe classique en R de définition d'un modèle (formulae) pour éviter un message d'erreur.
La constitution de l'échantillon test est similaire au traitement précédent avec une proportion identique.
In [ ]:
library(caret)
# indices de l'échantillon d'apprentissage
set.seed(xxx)
inTrain = createDataPartition(insee[,1], p = .7476, list = FALSE)
# Extraction des échantillons
# data frames apprentissage et test
inseeAppt=insee[inTrain,]
inseeTest=insee[-inTrain,]
Il est recommandé de centrer et réduire les variables quantitatives dans plusieurs méthodes. C'est fait systématiquement sauf dans le cas présent où les variables sont essentiellement qualitatives.
In [ ]:
# estimation des erreurs par validation croisée
cvControl=trainControl(method="cv",number=10)
La librairie intègre beaucoup plus de méthodes que celles utilisées. Consulter la liste des méthodes disponibles dans l'aide de la fonction: ?train
pour en tester d'autres. Exécuter successivement les blocs de commandes pour tracer séparamment chacun des graphes afin de contrôler le bon comportement de l'optimisation du paramètre ou des paramètres de complexité de chaque modèle.
L'utilisation de certaines méthodes, comme la régression logistique, est sans doute moins flexible qu'en utilisation "manuelle" en particulier dans le choix de l'algorithme de sélection de variables. Il faut se montrer (très) patient pour certaines optimisations alors que d'autres sont immédiates, voire inutiles. Le paramètre tuneLength
caractérise un effort
d'optimisation, c'est en gros le nombre de valeurs de paramètres testées sur une grille fixée automatiquement. En prenant plus de soin et aussi plus de temps, il est possible de fixer précisément des grilles pour les valeurs du ou des paramètres optimisés pour chaque méthode.
Q Pour chacune des méthodes ou algorithmes utilisés ci-dessous, préciser quels sont les paramètres à optimiser.
In [ ]:
glmFit = train(Asvi~.,data=inseeAppt,method = "glmStepAIC",trControl = cvControl)
glmFit
In [ ]:
set.seed(2)
nnetFit = train(Asvi~.,data=inseeAppt,
method = "nnet", tuneLength = 6,
trControl = cvControl)
nnetFit
In [ ]:
plot(nnetFit)
In [ ]:
set.seed(2)
rpartFit = train(Asvi~.,data=inseeAppt,
method = "rpart", tuneLength = 10,
trControl = cvControl)
rpartFit
In [ ]:
plot(rpartFit)
In [ ]:
set.seed(2)
rfFit = train(Asvi~.,data=inseeAppt,
method = "rf", tuneLength = 4,
trControl = cvControl)
rfFit
In [ ]:
plot(rfFit)
In [ ]:
set.seed(2)
gbmFit = train(Asvi~.,data=inseeAppt,
method = "gbm", tuneLength = 4,
trControl = cvControl)
gbmFit
In [ ]:
plot(gbmFit)
Remarque : plusieurs méthodes comme $k$-nn, les SVM, l'analyse discriminante ne sont pas exécutables directement du fait du caractère qualitatif des variables explicatives. Il faudrait les remplacer par des variables indicatrices des modalités ou les coordonnées des individus d'une AFC du tableau disjonctif complet, c'est-à-dire les composantes principales de l'ACP des profils lignes associée à cette AFC; coordonnées obtenues par une SVD du tableau disjonctif complet en considérant les métriques du chi2. Consulter la vignette sur l'AFCM pour plus de précisions. Ce serait encore d'autres stratégies à tester...
Cette stratégie (utilisation des coordonnées de l'AFCM) est mise en oeuvre pour la prévision d'une pathologie coronarienne.
In [ ]:
set.seed(2)
xgboostFit = train(Asvi~.,data=inseeAppt,
method = "xgbTree", tuneLength = 4,
trControl = cvControl)
plot(xgboostFit)
In [ ]:
models=list(rlog=glmFit,nnet=nnetFit,rtree=rpartFit,rf=rfFit,gbm=gbmFit,XGB=xgboostFit)
testPred=predict(models, newdata = inseeTest)
# taux de bien classés
lapply(testPred,function(x)mean(x==inseeTest[,"Asvi"]))
Tracer les courbes ROC pour analyser spécificité et sensibilité.
In [ ]:
# Courbes ROC
library(ROCR)
testProb=predict(models, newdata = inseeTest, type="prob")
predroc=lapply(testProb, function(x)prediction(x[,1], inseeTest[,"Asvi"]=="AsN"))
perfroc=lapply(predroc, function(x)performance(x, "tpr", "fpr"))
# Tracer les courbes ROC
options(repr.plot.width=8, repr.plot.height=8)
plot(perfroc$rlog,col=1)
plot(perfroc$nnet,col=2,add=TRUE)
plot(perfroc$rtree,col=3,add=TRUE)
plot(perfroc$rf,col=4,add=TRUE)
plot(perfroc$gbm,col=5,add=TRUE)
plot(perfroc$XGB,col=6,add=TRUE)
legend("bottomright",legend=c("rlog","nnet", "Tree","RF","gbm","XGB"),col=c(1:6),pch="_")
Q Comparer, commenter. Une méthodes est-elle à retenir ? A éviter ?
Certaines méthodes sont très peu explicites car de véritables "boîtes noires", quant au rôle et impact des variables sur la prévision des observations. Néanmoins, des indicateurs d'importance sont proposés pour les forêts aléatoires.
In [ ]:
rfFit2=randomForest(inseeAppt[,-1], inseeAppt[,"Asvi"],importance=T)
imp.mdrr=sort(rfFit2$importance[,3], decreasing=T)[1:20]
par(xaxt="n")
plot(imp.mdrr,type="h",ylab="Importance", xlab="Variables")
points(imp.mdrr,pch=20)
par(xaxt="s")
axis(1,at=1:20,labels=names(imp.mdrr), cex.axis=0.8,las=3)
Q Commenter ces importance notamment par rapport aux choix de variables en régression et dans l'arbre de décision.
L'échantillon n'est pas de faible taille, mais les estimations des taux de bien classés comme le tracé des courbes ROC sont très dépendants de l'échantillon test ; on peut s'interroger sur l'identité du modèle le plus performant comme sur la réalité des différences entre les méthodes. Il est alors important d'itérer le processus sur plusieurs échantillons tests aléatoires: validation croisée Monte Carlo.
Exécuter, c'est un peu long ... la fonction en annexe en choisissant les méthodes semblant les plus performantes:
In [ ]:
pred.insee=pred.autom(Asvi~.,data=insee,p = .7476,
methodes=c("glmStepAIC","nnet","rf","gbm","xgbTree"),N=10,
size=c(4,4,4,4,4),type="prob")
Puis calculer :
In [ ]:
# Taux de bien classés
obs=pred.insee$obs
prev.insee=pred.insee$pred
res.insee=lapply(prev.insee,function(x)apply((x>0.5)==(obs==1),2,mean))
# Moyennes des taux de bien classés par méthode
lapply(res.insee,mean)
# Distributions des taux de bien classés
boxplot(data.frame(res.insee))
# Tracer les courbes ROC moyennes
predroc.insee=lapply(prev.insee, function(x)prediction(x,obs==1))
perfroc.insee=lapply(predroc.insee, function(x)performance(x,"tpr","fpr"))
plot(perfroc.insee$glmStepAIC,col=1,lwd=1.5, avg="vertical")
plot(perfroc.insee$nnet,col=2,add=TRUE, lwd=1.5,avg="vertical")
plot(perfroc.insee$rf,col=3,add=TRUE, lwd=1.5,avg="vertical")
plot(perfroc.insee$gbm,add=TRUE,col=4,lwd=1.5, avg="vertical")
plot(perfroc.insee$xgbTree,add=TRUE,col=5,lwd=1.5, avg="vertical")
legend("bottomright",legend=c("rlogit","nnet", "RF", "boost", "XGB"),col=c(1:5),pch="_")
Q Commenter les résultats, peut-on conseiller une méthode ? Que dire du nombre très important de méthodes proposées au regard de ces résultats ?
Q Les fonctions de Scikit-learn
en python feront-t-elles mieux pour la qualité de prévision et le temps de calcul?
Attention
In [ ]:
pred.autom=function(formul,data,p=1/2,
methodes=c("knn","rf"),size=c(10,2),
xinit=11,N=10,typerr="cv",number=4,type="raw")
# Fonction de prévision de N échantillons tests
# par une liste de méthodes de régression
# ou classification (uniquement 2 classes)
# Optimisation des paramètres par validation
# croisée (défaut) ou bootstrap ou... (cf. caret)
# data : data frame avec la variable cible Y
# en première colonne
# Formule sous la forme Y~.
# p : proportion entre apprentissage et test
# methodes : liste des méthodes de discrimination
# size : e grille des paramètres à optimiser
# xinit : générateur de nombres aléatoires
# N : nombre de réplications apprentissage / test
# typerr : "cv" ou "boo" ou "oob"
# number : nombre de répétitions CV ou bootstrap
# pred : liste des matrices de prévision
{# type d'erreur
Control=trainControl(method=typerr,number=number)
# initialisation du générateur
set.seed(xinit)
# liste de matrices stockant les prévisions
# une par méthode
inTrain=createDataPartition(data[,1],p=p,list=FALSE)
ntest=length(data[-inTrain,1])
pred=vector("list",length(methodes))
names(pred)=methodes
pred=lapply(pred,function(x)x=matrix(0,
nrow=ntest,ncol=N))
obs=matrix(0,ntest,N)
set.seed(xinit)
for(i in 1:N) # N itérations
{# indices de l'échantillon d'apprentissage
inTrain=createDataPartition(data[,1],p=p,list=FALSE)
# Extraction des échantillons
Appt=data[inTrain,]
Test=data[-inTrain,]
# stockage des observés de testY
obs[,i]=Test[,1]
# estimation et optimisation des modèles
# pour chaque méthode de la liste
for(j in 1:length(methodes))
{# modélisation
modFit = train(formul,data=Appt,
method = methodes[j], tuneLength = size[j],
trControl = Control)
# prévisions
if (type=="prob") pred[[j]][,i]=predict(modFit,
newdata = Test,type=type)[,1]
else pred[[j]][,i]=predict(modFit,newdata=Test)
}}
list(pred=pred,obs=obs)} # résultats
In [ ]: