INTRODUCTION

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 :

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 :

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.

ANALYSE EXPLORATOIRE DES DONNEES

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.

Exploration numérique 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

Compréhension des variables

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 :

    • < 0 DM : le solde du compte courant est négatif. DM c’est le Deutsche Mark, l’ancienne monnaie allemande.
    • 1 - 200 DM : le solde est entre 1 (inclu) et 200 (inclu) DM.
    • unknown : le solde est inconnu.
    • > 200 DM : le solde est strictement supérieur à 200 DM.

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.

Données manquantes

Y a t-il des données manquantes ?

sum(is.na(credit))
## [1] 0

Exploration visuelle

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]))
}

CONSTRUCTION DES MODELES

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, ]

Arbre de décision

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

Forêts aléatoire (Random Forest)

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

CONCLUSION GENERALE

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.