Pour faire suite à mon article sur le Machine Learning, je vous propose de rentrer dans le vif du sujet. A travers ce petit rapport, j’aborde ,via des exemples, quelques problèmes de Classification, de Régression et de Clustering (Je préfère employer le mot clustering mais il faut le percevoir comme un groupement d’objets).
Le problème de Classification sera abordé avec le célèbre jeu de données titanic que vous pouvez télécharger ici. J’insisterai sur la Matrice de confusion pour discuter de la performance du modèle. On étudiera la régression avec les données air. A ce niveau on calculera le RMSE et on étudiera son évolution en fonction d’ajout de complexité dans le modèle. Pour terminer, nous étudierons le Clustering à travers le jeu de données seed. Je vous montrerai comment vous pouvez évaluer votre modèle selon la compacité de chaque groupe (cluster) et de leur séparation.
Par ailleurs, je souligne que pour ne pas alourdir le document, j’ai pris une partie propre de chaque jeu de donnée. Vous pouvez télécharger les vraies données utilisées dans ce document en suivant les liens ci-dessous. Cela vous permettra de refaire toute la procédure aec votre propre code et de comparer les résultats :).
titanic : Télécharger
air : Télécharger
seeds : Télécharger
Par ailleurs, vous pouvez aussi travailler ave les données brutes et passer préalablement par l’analyse exploratoire qui comprend bien évidemment le nettoyage des données. Dans un prochain document, je vous montrerai des techniques simples pour faire votre EDA.
ENJOY :)
# Importation des données. Notons que dans R, il y a un package "titanic" qui contient un jeu de données Titanic.
titanic <- read.csv("titanic.csv")
# Strucure des données
str(titanic)
## 'data.frame': 714 obs. of 4 variables:
## $ Survived: int 0 1 1 1 0 0 0 1 1 1 ...
## $ Pclass : int 3 1 3 1 3 1 3 3 2 3 ...
## $ Sex : Factor w/ 2 levels "female","male": 2 1 1 1 2 2 2 1 1 1 ...
## $ Age : num 22 38 26 35 35 54 2 27 14 4 ...
# Résumé statistique des variables de type numérique
summary(titanic)
## Survived Pclass Sex Age
## Min. :0.0000 Min. :1.000 female:261 Min. : 0.42
## 1st Qu.:0.0000 1st Qu.:1.000 male :453 1st Qu.:20.12
## Median :0.0000 Median :2.000 Median :28.00
## Mean :0.4062 Mean :2.237 Mean :29.70
## 3rd Qu.:1.0000 3rd Qu.:3.000 3rd Qu.:38.00
## Max. :1.0000 Max. :3.000 Max. :80.00
Notre jeu de données *titanic* fournit les informations sur le sort (a survécu ou a péri) de 714 passagers selon leur âge ( variable *Age*), leur sex (*Sex*) et leur classe économique (*Pclass*). Il est aussi intéressant de représenter la distribution des variables.
# titanic$Survived as factor : yes pour 1 (les survivants) et no pour 0 (ceux qui ont péri)
titanic$Survived <- as.factor(titanic$Survived)
#titanic$Pclass as factor. Il y a en fait 3 niveaux de classe économique : 1ère, 2ème et 3ème.
titanic$Pclass <- as.factor(titanic$Pclass)
# Représentation graphique des variables catégorielles
library(ggplot2)
# titanic en format long
titanic_factor <- titanic %>%
select_if(is.factor) %>%
gather(key = "variable", value = "valeur")
ggplot(titanic_factor, aes(valeur)) +
geom_bar() +
facet_wrap(~ variable, scales = "free_x")
Il y a plus de personnes de troisième classe économique, plus d’hommes que de femmes et plus de morts que de survivants.
N’oubliez pas que pour les algorithmes ayant un aspect aléatoire en leur sein, il faut toujours s’assurer de la reproductibilité du code.
library(rpart)
# Reproductibilité
set.seed(123)
# Formation du modèle
arbre <- rpart(Survived ~ ., data = titanic, method = "class")
# Prédiction. La prédiction est faite sur le même jeu de données titanic pour voir si le modèle rend bien compte de la réalité.
pred1 <- predict(arbre, type = "class")
# Visualisation du modèle
library(rpart.plot)
rpart.plot(arbre, yesno = 2)
Normalement, on fait la prédiction sur un jeu de données étiquetées que le modèle n’a jamais vu afin de s’assurer vraiment s’il peut être opérationnel ou pas. Mais le modèle n’est t-il pas censé bien représenter les données qui ont servi à sa formation ? C’est ce que nous allons vérifié avec la matrice de confusion.
La matrice de confusion donne 04 valeurs :
TP (True Positive) : Les survivants correctement prédit par le modèle comme ayant survécu ;
FP (False Positive) : Les personnes décédées qui ont été prédit à tort par le modèle comme étant des survivants au naufrage.
FN (False Negative) : Les survivants ayant été prédit à tort par le modèle comme ayant péris.
TN (True Negative) : Les personnes décédées correctement prédit par le modèle comme personnes ayant péri dasn le Naufrage.
#Matrice de confusion
conf <- table(titanic$Survived, pred1)
conf
## pred1
## 0 1
## 0 371 53
## 1 78 212
#Composants de la matrice de confusion. TP : True Positive, FP : False Positive, FN : False Negative, TN : True Negative
TN <- conf[1, 1]
FN <- conf[2, 1]
FP <- conf[1, 2]
TP <- conf[2, 2]
# Précision globale : c'est la diagonale de la matrice
precision_globale <- (TP+TN)/(TP+FP+FN+TN)
precision_globale
## [1] 0.8165266
# Les réels survivants du jeu de données titanic sont au nombre de :
TP+FP # Personnes ayant réellement survécu au naufrage
## [1] 265
# Les personnes réellement décédées du jeu de données titanic sont au nombre de :
FN+TN # Personnes réellement décédées
## [1] 449
Avec une précision globale d’environ 82%, le modèle n’a prédit à tort que 18% du destin des passagers. Globalement, on peut dire que le modèle est acceptable mais en réalité il n’est pas vraiment satisfaisant.
Sachez que le choix du paramètre d’évaluation d’un modèle doit être fait au cas par cas selon le contexte de votre étude et l’objectif que vous visez. Le paramètre précision globale qui découle de la matrice de confusion peut dans certains cas ne pas être adéquat pour mesurer la performance d’un modèle de classification. Dans un prochain article, on étudiera un jeu de données médicales (classification pour l’aide au diagnostique de cancer) et je vous montrerai que même si la précision globale est élevée,cela ne signifie pas forcément que le modèle est performant et qu’il peut être déployé.
Dans la pratique, on étudie plusieurs paramètres pour évaluer la performance d’un modèle.
# Importation des données
air <- read.csv("air.csv")
# Structure des données
str(air)
## 'data.frame': 1503 obs. of 6 variables:
## $ freq : int 800 1000 1250 1600 2000 2500 3150 4000 5000 6300 ...
## $ angle : num 0 0 0 0 0 0 0 0 0 0 ...
## $ ch_length: num 0.305 0.305 0.305 0.305 0.305 ...
## $ velocity : num 71.3 71.3 71.3 71.3 71.3 71.3 71.3 71.3 71.3 71.3 ...
## $ thickness: num 0.00266 0.00266 0.00266 0.00266 0.00266 ...
## $ dec : num 126 125 126 128 127 ...
# Résumé statistique des variables numériques
summary(air)
## freq angle ch_length velocity
## Min. : 200 Min. : 0.000 Min. :0.0254 Min. :31.70
## 1st Qu.: 800 1st Qu.: 2.000 1st Qu.:0.0508 1st Qu.:39.60
## Median : 1600 Median : 5.400 Median :0.1016 Median :39.60
## Mean : 2886 Mean : 6.782 Mean :0.1365 Mean :50.86
## 3rd Qu.: 4000 3rd Qu.: 9.900 3rd Qu.:0.2286 3rd Qu.:71.30
## Max. :20000 Max. :22.200 Max. :0.3048 Max. :71.30
## thickness dec
## Min. :0.0004007 Min. :103.4
## 1st Qu.:0.0025351 1st Qu.:120.2
## Median :0.0049574 Median :125.7
## Mean :0.0111399 Mean :124.8
## 3rd Qu.:0.0155759 3rd Qu.:130.0
## Max. :0.0584113 Max. :141.0
Le jeu de données “air” donne la pression acoustique dec produite par l’aile d’un avion selon différents paramètres comme la fréquence du vent (fred), l’angle de vol (angle), la vitesse de vol (velocity), l’épaisseur de l’aile () et sa longueur (ch_length).
Nous alons construire dans un premier temps un modèle de régression multivariable qui prédit la pression acoustique de l’aile en fonction de la fréquence du vent, de l’angle de vol et de la longueur de l’aile. Ensuite, nous ajouterons plus de complexité au modèle en ajoutant les autres variables.
# Les Deux modèles
reg1 <- lm(dec ~ freq + angle + ch_length, data = air)
reg2 <- lm(dec ~ freq + angle + ch_length + velocity + thickness, data = air)
# Paramètres des modèles
summary(reg1)
##
## Call:
## lm(formula = dec ~ freq + angle + ch_length, data = air)
##
## Residuals:
## Min 1Q Median 3Q Max
## -17.212 -3.251 0.054 3.310 20.143
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.381e+02 4.427e-01 312.03 <2e-16 ***
## freq -1.200e-03 4.509e-05 -26.62 <2e-16 ***
## angle -6.664e-01 2.783e-02 -23.95 <2e-16 ***
## ch_length -3.885e+01 1.694e+00 -22.94 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 5.223 on 1499 degrees of freedom
## Multiple R-squared: 0.428, Adjusted R-squared: 0.4269
## F-statistic: 373.9 on 3 and 1499 DF, p-value: < 2.2e-16
summary(reg2)
##
## Call:
## lm(formula = dec ~ freq + angle + ch_length + velocity + thickness,
## data = air)
##
## Residuals:
## Min 1Q Median 3Q Max
## -17.480 -2.882 -0.209 3.152 16.064
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.328e+02 5.447e-01 243.87 <2e-16 ***
## freq -1.282e-03 4.211e-05 -30.45 <2e-16 ***
## angle -4.219e-01 3.890e-02 -10.85 <2e-16 ***
## ch_length -3.569e+01 1.630e+00 -21.89 <2e-16 ***
## velocity 9.985e-02 8.132e-03 12.28 <2e-16 ***
## thickness -1.473e+02 1.501e+01 -9.81 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.809 on 1497 degrees of freedom
## Multiple R-squared: 0.5157, Adjusted R-squared: 0.5141
## F-statistic: 318.8 on 5 and 1497 DF, p-value: < 2.2e-16
# Prédiction
pred_reg1 <- predict(reg1)
pred_reg2 <- predict(reg2)
Si vous avez une data frame (df) avec une variable-cible y, alors le rmse se calcule par la formule :
rmse = sqrt((1/nrow(df))*sum((df$y-pred)^2)) où pred est le vecteur de valeurs prédites par le modèle pour la variable y.
On peut facilement se perdre dans toutes ses parenthèses. Heureusement qu’il y a une fonction rmse dans R pour calculer le rmse du modèle.
library(Metrics)
rmse1 <- rmse(actual = air$dec, predicted = pred_reg1)
rmse1 # rmse du 1er modèle
## [1] 5.215778
rmse2 <- rmse(actual = air$dec, predicted = pred_reg2)
rmse2 # rmse du 2ème modèle
## [1] 4.799244
Le rmse du premier modèles est égal à 5,215 décibels (unité demesure de la pression acoustique). Mais ce chiffre en lui-même ne nous aide pas beaucoup. Qu’est-ce que nous pouvons en tirer quant à la performance du modèle ?
Le rmse du deuxième model (plus complexe que le premier à cause de l’ajout d’autres variables prédictrices) est égal à environ 4,8 donc inférieur à celui du premier modèle.
Il faut comprendre qu’une valeur de rmse égal à 0 (pratiquement jamais atteinte dans la pratique) indiquerait un ajustement parfait aux données. En général, un RMSE inférieur est préférable à un plus élevé.
Donc, par rapport au paramètre rmse, nous choisirons plutôt le deuxième modèle pred_reg2. Notre choix est confirmé par le R² (c’est la variance expliquée par le modèle) de chacun des modèles. 42,8% de la variance est expliquée par le modèle pred_reg1 alors qu’environ 51,6% de la variance est expliquée par le modèle 2 : pred_reg2. S’il est vrai que selon ces paramètres (RMSE et R²), le deuxième modèle est plus performant que le premier, il n’en demeurre pas moins que leurs performances ne sont pas satisfaisantes (R² faible).
# Importation des données
seeds <- read.csv("seeds.csv")
# Structure des données
str(seeds)
## 'data.frame': 210 obs. of 7 variables:
## $ area : num 15.3 14.9 14.3 13.8 16.1 ...
## $ perimeter : num 14.8 14.6 14.1 13.9 15 ...
## $ compactness : num 0.871 0.881 0.905 0.895 0.903 ...
## $ length : num 5.76 5.55 5.29 5.32 5.66 ...
## $ width : num 3.31 3.33 3.34 3.38 3.56 ...
## $ asymmetry : num 2.22 1.02 2.7 2.26 1.35 ...
## $ groove_length: num 5.22 4.96 4.83 4.8 5.17 ...
# Résumé statistique
summary(seeds)
## area perimeter compactness length
## Min. :10.59 Min. :12.41 Min. :0.8081 Min. :4.899
## 1st Qu.:12.27 1st Qu.:13.45 1st Qu.:0.8569 1st Qu.:5.262
## Median :14.36 Median :14.32 Median :0.8734 Median :5.524
## Mean :14.85 Mean :14.56 Mean :0.8710 Mean :5.629
## 3rd Qu.:17.30 3rd Qu.:15.71 3rd Qu.:0.8878 3rd Qu.:5.980
## Max. :21.18 Max. :17.25 Max. :0.9183 Max. :6.675
## width asymmetry groove_length
## Min. :2.630 Min. :0.7651 Min. :4.519
## 1st Qu.:2.944 1st Qu.:2.5615 1st Qu.:5.045
## Median :3.237 Median :3.5990 Median :5.223
## Mean :3.259 Mean :3.7002 Mean :5.408
## 3rd Qu.:3.562 3rd Qu.:4.7687 3rd Qu.:5.877
## Max. :4.033 Max. :8.4560 Max. :6.550
Le jeu de données seeds donne les mesures de différents paramètres de 210 semences (graines). Le problème est qu’on ne connait pas quelles mesures pour quel type de graine (données non étiquetées). On choisit de grouper les graines en 3 types avec l’algorithme K-means pour le clustering.
# Reproductibilité
set.seed(123)
# Modèle
clust <- kmeans(seeds, centers = 3)
summary(clust)
## Length Class Mode
## cluster 210 -none- numeric
## centers 21 -none- numeric
## totss 1 -none- numeric
## withinss 3 -none- numeric
## tot.withinss 1 -none- numeric
## betweenss 1 -none- numeric
## size 3 -none- numeric
## iter 1 -none- numeric
## ifault 1 -none- numeric
# Graphique montrant les clusters
# Représentons par exemple les observations avec les variables compactness ~ length colorées par les clusters.
plot(length ~ compactness, data = seeds, col = clust$cluster)
L’évaluation d’un modèle de clustering consiste, entres autres méthodes, à vérifier si les groupes (les clusters) sont bien séparés entre eux et si chaque cluster est bien compact.
# Vérifier si les groupes sont bien séparés
clust$betweenss
## [1] 2132.534
# Vérifier si les clusters sont compacts
clust$tot.withinss
## [1] 587.3186
# Ratio
clust$tot.withinss/clust$betweenss
## [1] 0.2754088
On constate que clust\(tot.withinss* est largement inférieur à *clust\)betweenss. Le ratio est de 0,27. Donc les groupes sont bien compactes. Le graphique aussi le montre bien. Il est donc probable que ces trois clusters (groupes) représentent bien les trois types de semences (graines), même s’il n’existe pas de données étiquetées pour vérifier cela.
Ce type de technique de Machine Learning est tr-s utilisé en Marketing où on effectue le clustering des clients afin d’avoir des groupes distincts de clients de même caractéristiques pour leur adresser des publicités ciblées.
Dans ce rapport, nous avons étudié de manière simplifiée Trois différents problèmes conernant respectivement la Classification, la Régression et le Clustering.
Pour le modèle de Classification, nous avons utilisé la matrice de Confusion pour évaluer la qualité du modèle.
En ce qui concerne le modèle de Régression, nous avons calculé le RMSE pour évaluer les deux modèles construits. Notre choix final a été confirmé par le R², paramètre donnant la variance expliquée par le modèle.
Pour finir, nous avons appliqué l’algorithme de clustering kmeans afin de grouper les semences de même caractéristique. Soulignons que dans la pratique, le nombre de cluster est déterminé soit par connaissance du phénomène (l’expérience joue à ce niveau) ou soit on choisit le nombre de cluster optimal. Dans un autre document, j’expliquerai cela en détail.
Merci pour la lecture de ce petit document et à bientôt pour d’autres documents sur le Machine Learning.