Selon Wikipédia, L’apprentissage automatique (Machine Learning en anglais) ou apprentissage statistique est un champ d’étude de l’intelligence artificielle qui se fonde sur des approches mathématiques et statistiques pour donner aux ordinateurs la capacité d’ « apprendre » à partir de données, c’est-à-dire d’améliorer leurs performances à résoudre des tâches sans être explicitement programmés pour chacune. Plus largement, il concerne la conception, l’analyse, l’optimisation, le développement et l’implémentation de telles méthodes.
Il existe trois (03) types majeurs d’apprentissage automatique :
Apprentissage non supervisé (Unsupervised Learning en anglais) : Le but de l’apprentissage non supervisé est de trouver des structures sous-jacentes à partir de données non étiquetées.
Apprentissage supervisé (Supervised Learning en anglais) : Contrairement à l’apprentissage non supervisé, l’apprentissage supervisé fait les prédictions sur la base de données étiquetées. En apprentissage supervisé on a deux (02) types de problème :
Apprentissage par renforcement (Reinforcement Learning en anglais) : Il ne faut pas confondre ce type de machine learning avec l’apprentissage supervisé. C’est beaucoup plus avancé ! Regardez cette belle vidéo explicative. Pour faire simple, cette méthode consiste à laisser l’algorithme apprendre de ses propres erreurs. Il y a un système de récompense et de pénalité qui est mis en place. Grâce à ce système, l’IA va faire de son mieux pour prendre les bonnes décisions afin d’avoir plus de récompenses.
Dans cet article, nous intéressons à l’apprentissage supervisé particulièrement aux méthodes d’arborescence c’est-à-dire les méthodes basées sur les arbres. Nous étudierons les différentes techniques suivantes :
Arbre de classification (Classification Tree);
Forêts aléatoires (Random Forest en anglais) ;
Un arbre de décision est un outil d’aide à la décision représentant un ensemble de choix sous la forme graphique d’un arbre. Dans le modèle d’arbre de décision, on utilise un ensemble de données pour lesquelles on connaît la valeur de la variable-cible (données dites étiquetées) afin de construire l’arbre, puis on extrapole les résultats à l’ensemble des données de test.
Afin d’améliorer la qualité ou la fiabilité de la prédiction, plusieurs techniques ont été développées et sont appelées méthodes d’ensemble dont fait partie les forêts aléatoires.
Les deux (02) modèles cités ci-dessus seront formés sur le même ensemble de données d’entrainement (training data), et des prévisions seront établies pour le même jeu de données test (test data). Ce faisant, nous pourrons donc comparer les modèles surla base d’un même paramètre.
Cette étude a été réalisée avec des données libres du Crédit Allemand. Ces données archivées sont mises à disposition du public dans le cadre de l’Open Data pour la formation en Machine Learning.
Toute étude en Data Science doit commencer par une analyse exploiratoire aussi bien nulérique que visuelle des données.
credit <- read.csv("credit.csv")
#Dimension des données
dim(credit)
## [1] 1000 17
#Structure des données
str(credit)
## 'data.frame': 1000 obs. of 17 variables:
## $ checking_balance : Factor w/ 4 levels "< 0 DM","> 200 DM",..: 1 3 4 1 1 4 4 3 4 3 ...
## $ months_loan_duration: int 6 48 12 42 24 36 24 36 12 30 ...
## $ credit_history : Factor w/ 5 levels "critical","good",..: 1 2 1 2 4 2 2 2 2 1 ...
## $ purpose : Factor w/ 6 levels "business","car",..: 5 5 4 5 2 4 5 2 5 2 ...
## $ amount : int 1169 5951 2096 7882 4870 9055 2835 6948 3059 5234 ...
## $ savings_balance : Factor w/ 5 levels "< 100 DM","> 1000 DM",..: 5 1 1 1 1 5 4 1 2 1 ...
## $ employment_duration : Factor w/ 5 levels "< 1 year","> 7 years",..: 2 3 4 4 3 3 2 3 4 5 ...
## $ percent_of_income : int 4 2 2 2 3 2 3 2 2 4 ...
## $ years_at_residence : int 4 2 3 4 4 4 4 2 4 2 ...
## $ age : int 67 22 49 45 53 35 53 35 61 28 ...
## $ other_credit : Factor w/ 3 levels "bank","none",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ housing : Factor w/ 3 levels "other","own",..: 2 2 2 1 1 1 2 3 2 2 ...
## $ existing_loans_count: int 2 1 1 1 2 1 1 1 1 2 ...
## $ job : Factor w/ 4 levels "management","skilled",..: 2 2 4 2 2 4 2 1 4 1 ...
## $ dependents : int 1 1 2 2 2 2 1 1 1 1 ...
## $ phone : Factor w/ 2 levels "no","yes": 2 1 1 1 1 2 1 2 1 1 ...
## $ default : Factor w/ 2 levels "no","yes": 1 2 1 1 2 1 1 1 1 2 ...
#Résumé statistique
summary(credit)
## checking_balance months_loan_duration credit_history
## < 0 DM :274 Min. : 4.0 critical :293
## > 200 DM : 63 1st Qu.:12.0 good :530
## 1 - 200 DM:269 Median :18.0 perfect : 40
## unknown :394 Mean :20.9 poor : 88
## 3rd Qu.:24.0 very good: 49
## Max. :72.0
## purpose amount savings_balance
## business : 97 Min. : 250 < 100 DM :603
## car :337 1st Qu.: 1366 > 1000 DM : 48
## car0 : 12 Median : 2320 100 - 500 DM :103
## education : 59 Mean : 3271 500 - 1000 DM: 63
## furniture/appliances:473 3rd Qu.: 3972 unknown :183
## renovations : 22 Max. :18424
## employment_duration percent_of_income years_at_residence age
## < 1 year :172 Min. :1.000 Min. :1.000 Min. :19.00
## > 7 years :253 1st Qu.:2.000 1st Qu.:2.000 1st Qu.:27.00
## 1 - 4 years:339 Median :3.000 Median :3.000 Median :33.00
## 4 - 7 years:174 Mean :2.973 Mean :2.845 Mean :35.55
## unemployed : 62 3rd Qu.:4.000 3rd Qu.:4.000 3rd Qu.:42.00
## Max. :4.000 Max. :4.000 Max. :75.00
## other_credit housing existing_loans_count job
## bank :139 other:108 Min. :1.000 management:148
## none :814 own :713 1st Qu.:1.000 skilled :630
## store: 47 rent :179 Median :1.000 unemployed: 22
## Mean :1.407 unskilled :200
## 3rd Qu.:2.000
## Max. :4.000
## dependents phone default
## Min. :1.000 no :596 no :700
## 1st Qu.:1.000 yes:404 yes:300
## Median :1.000
## Mean :1.155
## 3rd Qu.:1.000
## Max. :2.000
Notre jeu de données comporte 1000 observations (c’est-à-dire 1000 emprunteurs) et 17 variables. Il est importat de comprendrela signification de chacune de ces varibales :
checking_balance : il s’agit du solde du compte courant. Concernant les prêts bancaires, cette variable est naturellement très importante. En effet si vous êtes candidat à un prêt et que votre compte courant est à découvert ou est fréquemment à découvert, cela risque fortement de jouer en votre défaveur. On remarque que cette variable prend les valeurs suivantes :
On peut voir ces différentes valeurs grâce à la fonction unique(). La variable checking_balance est donc vraiment une variable catégorielle.
months_loan_duration : Cette variable représente la durée en mois du crédit. C’est une varibale de type numérique.
credit_history : cette variable définit les antécédents en matière de prêt (crédit) du client. Elle prend les valeurs suivantes : critical (le compte critique c’est-à-dire que le client a d’autres crédits en cours dans d’autres banques.), poor, good, perfect, very good. Il s’agit donc d’une variable catégorielle.
purpose : cette variable représente le motif du prêt. Exemple : On fait un prêt immobilier pour construire sa maison ou acheter une maison et un prêt auto pour acheter une voiture. Les valeurs prises par cette variable sont : furniture/appliances, education, car (voiture d’occasion), business, renovations, car0 (voiture neuve).
amount : montant du prêt.
savings_balance : c’est le solde du compte épargne. Cette variable catégorielle prend les valeurs suivantes : unknown, < 100 DM, 100 - 500 DM, 500 - 1000 DM et > 1000 DM.
employment_duration : représente la durée de l’emploi, c’est-à-dire le client occupe son emploi actuel depuis quand. Les différentes valeurs prises par cette variable sont : unemployed (chômeur), < 1 year, 1 - 4 years, 4 - 7 years et 7 years.
percent_of_income : cette variable représente le Taux de versement en pourcentage du revenu disponible. C’est donc bel et bien une variable numérique.
years_at_residence : Cette variable désigne le nombre d’années depuis lequel le client rest résident dans cette banque.
age : représente l’âge du client.
other_credit : Autres crédits. Différentes valeurs : none, bank et store
housing : Cette variable catégorielle définit si le client possède sa propre maison (own), ou s’il est en location (rent), ou s’il se trouve dans d’autres cas (other)
existing_loans_count : Nombre de crédits déjà en cours.
job : défnit si le client occupe un emploi qualifié (skilled), non qualifié (unskilled), de manageur (management) ou s’il est tout simplement chômeur (unemployed).
dependents : Nombre de personnes à charge du client.
phone : Variable catégorielle qui définit si le client a un téléphone enregistré en son nom (yes) ou pas (no).
default : Cette variable définit si le client est en défaut de remboursement de son crédit (yes) ou pas (no). Dans le cadre de cette étude, cette variable est notre variable-cible.
Les banques collectent plusieurs tyoes de données sur leurs clients qui peuvent leur permettre de déterminer les clients à risque en matière de prêts bancaires et ainsi limiter les dégâts.
Y a t-il des données manquantes ?
sum(is.na(credit))
## [1] 0
Le résumé statistique nous a permit d’avoir une description chiffrée des données numériques. Il est aussi judicieux d’explorer également la relation par paires entre toutes les variables de type numérique de l’ensemble des données en utilisant une matrice de coorrélation.
#Matrice de corrélation
library(corrplot)
credit %>%
select_if(is.integer) %>%
cor() %>%
corrplot()
Explorons à présent les distributions des variables catégorielles
credit_factor <- credit %>%
select_if(is.factor)
n <- ncol(credit_factor)
noms_col <- names(credit)
for (i in 1 : n) {
plot(credit_factor[i], main = toString(noms_col[i]))
}
Commencçons d’abord par scinder l’ensemble de nos données en 02 parties 80/20 : une partie pour l’entraînement du modèle (credit_train) qui va représenter 80% du total et l’autre partie pour tester le modèle (credit_test).
n_train <- round(0.80 * nrow(credit))
set.seed(123) #set.seed() pour assurer la reproductibilité
train_indices <- sample(1:nrow(credit), n_train)
credit_train <- credit[train_indices, ]
credit_test <- credit[-train_indices, ]
Il s’agit précisement d’un abre de classificaion (Ici classification binaire yes ou no).
L’idée derrière l’arbre de classification est de diviser les données en sous-ensembles où chaque sous-ensemble appartient à seulement une classe. La meilleure division est celle qui donne des sous-ensembles beaucoup plus homogènes c’est-à-dire des sous-ensembles purs.
library(rpart)
#Construction du modèle
model_tree <- rpart(default ~ ., data = credit_train, method = "class")
#Résultats
library(rpart.plot)
rpart.plot(x = model_tree, yesno = 2) #yesno est un argument facultatif
print(model_tree)
## n= 800
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 800 238 no (0.70250000 0.29750000)
## 2) checking_balance=> 200 DM,unknown 369 45 no (0.87804878 0.12195122) *
## 3) checking_balance=< 0 DM,1 - 200 DM 431 193 no (0.55220418 0.44779582)
## 6) months_loan_duration< 20.5 231 84 no (0.63636364 0.36363636)
## 12) credit_history=critical,good,poor 207 66 no (0.68115942 0.31884058)
## 24) amount< 7341 200 60 no (0.70000000 0.30000000) *
## 25) amount>=7341 7 1 yes (0.14285714 0.85714286) *
## 13) credit_history=perfect,very good 24 6 yes (0.25000000 0.75000000) *
## 7) months_loan_duration>=20.5 200 91 yes (0.45500000 0.54500000)
## 14) savings_balance=> 1000 DM,unknown 35 9 no (0.74285714 0.25714286)
## 28) amount>=2079 26 2 no (0.92307692 0.07692308) *
## 29) amount< 2079 9 2 yes (0.22222222 0.77777778) *
## 15) savings_balance=< 100 DM,100 - 500 DM,500 - 1000 DM 165 65 yes (0.39393939 0.60606061)
## 30) months_loan_duration< 47.5 132 60 yes (0.45454545 0.54545455)
## 60) age>=29.5 77 35 no (0.54545455 0.45454545)
## 120) amount>=2249 62 24 no (0.61290323 0.38709677)
## 240) credit_history=critical,poor,very good 25 5 no (0.80000000 0.20000000) *
## 241) credit_history=good,perfect 37 18 yes (0.48648649 0.51351351)
## 482) age< 41 21 7 no (0.66666667 0.33333333) *
## 483) age>=41 16 4 yes (0.25000000 0.75000000) *
## 121) amount< 2249 15 4 yes (0.26666667 0.73333333) *
## 61) age< 29.5 55 18 yes (0.32727273 0.67272727)
## 122) months_loan_duration< 31.5 38 16 yes (0.42105263 0.57894737)
## 244) amount>=3415 17 6 no (0.64705882 0.35294118) *
## 245) amount< 3415 21 5 yes (0.23809524 0.76190476) *
## 123) months_loan_duration>=31.5 17 2 yes (0.11764706 0.88235294) *
## 31) months_loan_duration>=47.5 33 5 yes (0.15151515 0.84848485) *
#Prédictions du modèle
pred1 <- predict(object = model_tree, newdata = credit_test, type = "class")
#Performance du modèle par mesure de l'erreur de classification
library(ModelMetrics)
(ce1 <- ce(actual = credit_test$default, predicted = pred1))
## [1] 0.295
Les forêts aléatoires sont des ensembles d’arbres formés sur des échantillons bootstrapés des données d’entrainement (training data) du modèle. La principale différence de cette technique avec d’autres méthodes ensemblistes est que lors de la formation des arbres qui composent l’ensemble, on ajoute un peu d’aléatoire supplémentaire au modèle. En effet, dans les forêts alétaoires seul un sous-ensemble de variables est sélectionné de manière aléatoire à chaque division dans un arbre de décision alors que dans les arbres ensachés (bagged trees) par exemple toutes les variables sont utilisées à chaque division dans un arbre.
Plus il y a d’arbres (plus l’argument ntree est grand) dans la forêt, plus le modèle est performant. Mais à partir d’un certain seuil de nombre d’arbres, ajouter plus d’arbres n’améliore plus la performance du modèle. Donc il faudra déterminer ce nombre optimal d’arbres.
library(randomForest)
## randomForest 4.6-14
## Type rfNews() to see new features/changes/bug fixes.
##
## Attaching package: 'randomForest'
## The following object is masked from 'package:dplyr':
##
## combine
## The following object is masked from 'package:ggplot2':
##
## margin
#Construction du modèle
model_forest <- randomForest(formula = default ~ ., data = credit_train)
print(model_forest)
##
## Call:
## randomForest(formula = default ~ ., data = credit_train)
## Type of random forest: classification
## Number of trees: 500
## No. of variables tried at each split: 4
##
## OOB estimate of error rate: 24.75%
## Confusion matrix:
## no yes class.error
## no 512 50 0.08896797
## yes 148 90 0.62184874
#Prédictions
pred2 <- predict(object = model_forest, newdata = credit_test, type = "class")
#Performance du modèle
(ce2 <- ce(actual = credit_test$default, predicted = pred2))
## [1] 0.23
ce2 < ce1
## [1] TRUE
Le modèle des forêts aléatoires est plus performant que celui du simple arbre de classification.
A travers cette étude, nous avons montré comment effectuer de manière simple une modélisation par les arbres de décision dans le logiciel R. Les forêts aléatoires sont un puissant algorithme de machine learning qu’on peut utiliser dans plusieurs domaines.
Nous pouvons augmenter les performances du modèle en étudiant les hyperparamètres. De plus, au lieu d’un simple Training/Set, nous pouvons effectuer une validation croisée afin de mieux prendre en compte la variance dans les données.