Le diabète de type 2 est une maladie chronique qui touche des millions de personnes à travers le monde. Il constitue un enjeu majeur de santé publique en raison de ses complications graves (cardiovasculaires, rénales, neurologiques) et de son impact économique sur les systèmes de santé. La prévention et le dépistage précoce sont donc essentiels pour limiter sa progression et améliorer la qualité de vie des patients.
Dans ce projet, l’objectif est de prédire la probabilité qu’un individu soit atteint de diabète de type 2 à partir de variables cliniques mesurées lors d’un examen médical. Cette approche s’inscrit dans une logique de médecine préventive appuyée par l’intelligence artificielle et l’analyse statistique.
Pour cela, nous utilisons la base de données
PimaIndiansDiabetes2 issue du package
mlbench. Cette base contient des informations cliniques sur
des femmes d’origine Pima (population amérindienne), incluant des
variables telles que la glycémie, la pression artérielle, l’indice de
masse corporelle (IMC), l’âge, et d’autres indicateurs pertinents. Elle
est largement utilisée dans la communauté scientifique pour tester des
modèles de classification supervisée.
Plusieurs chercheurs ont exploré cette base dans des travaux récents. Par exemple, Ali, Galal et Hassan (2025) ont développé un pipeline de machine learning robuste pour prédire le diabète à partir de cette base, en appliquant des techniques d’imputation, de normalisation et d’ensembles de modèles. De même, Arora, Sehgal, Sharma, Nayak et Kumar (2024) ont comparé différentes méthodes de fouille de données pour améliorer la précision du diagnostic précoce du diabète à l’aide de cette même base.
La base de données PimaIndiansDiabetes2 contient des
observations cliniques de femmes d’origine Pima âgées de 21 ans ou plus.
Chaque ligne représente un individu, et les colonnes correspondent à des
variables médicales utilisées pour prédire la présence ou non de diabète
de type 2. Voici les variables disponibles :
Certaines valeurs manquantes sont codées comme NA,
notamment pour les variables glucose,
pressure, triceps, insulin, et
mass. Il est donc nécessaire de les traiter lors du
prétraitement des données.
Avant toute modélisation, il est essentiel d’identifier les valeurs manquantes dans la base. Cela permet de décider s’il faut les imputer, les supprimer ou les traiter autrement.
library(mlbench)
## Warning: le package 'mlbench' a été compilé avec la version R 4.4.3
library(tidyverse)
## Warning: le package 'tidyverse' a été compilé avec la version R 4.4.3
## Warning: le package 'ggplot2' a été compilé avec la version R 4.4.2
## Warning: le package 'dplyr' a été compilé avec la version R 4.4.2
## Warning: le package 'lubridate' a été compilé avec la version R 4.4.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(naniar)
## Warning: le package 'naniar' a été compilé avec la version R 4.4.3
data(PimaIndiansDiabetes2)
df <- PimaIndiansDiabetes2
# Visualisation des valeurs manquantes avec couleurs personnalisées
vis_miss(df) +
theme_minimal() +
labs(title = "Visualisation des valeurs manquantes",
subtitle = "Présent (grise) vs Manquant (rouge)",
x = "Variables",
y = "Observations") +
scale_fill_manual(values = c("grey", "red"),
name = "Statut",
labels = c("Présent", "Manquant"))
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
# Aperçu des données manquantes
summary(df)
## pregnant glucose pressure triceps
## Min. : 0.000 Min. : 44.0 Min. : 24.00 Min. : 7.00
## 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 64.00 1st Qu.:22.00
## Median : 3.000 Median :117.0 Median : 72.00 Median :29.00
## Mean : 3.845 Mean :121.7 Mean : 72.41 Mean :29.15
## 3rd Qu.: 6.000 3rd Qu.:141.0 3rd Qu.: 80.00 3rd Qu.:36.00
## Max. :17.000 Max. :199.0 Max. :122.00 Max. :99.00
## NA's :5 NA's :35 NA's :227
## insulin mass pedigree age diabetes
## Min. : 14.00 Min. :18.20 Min. :0.0780 Min. :21.00 neg:500
## 1st Qu.: 76.25 1st Qu.:27.50 1st Qu.:0.2437 1st Qu.:24.00 pos:268
## Median :125.00 Median :32.30 Median :0.3725 Median :29.00
## Mean :155.55 Mean :32.46 Mean :0.4719 Mean :33.24
## 3rd Qu.:190.00 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :846.00 Max. :67.10 Max. :2.4200 Max. :81.00
## NA's :374 NA's :11
# Visualisation professionnelle des valeurs manquantes
vis_miss(df) # Visualisation graphique des valeurs manquantes
Notre graphique précise que notre jeu de données contient 9,4 % de
valeurs manquantes au total (contre 90,6 % de valeurs observées). Nous
présentons le tableau ci dessus pour une explication des variables
manquantes. ### Tableau : Taux de valeurs manquantes et
interprétation
| Variable | % de valeurs manquantes | Interprétation |
|---|---|---|
pregnant |
0 % | Aucun manque, variable complète. |
glucose |
1 % | Très peu de données manquantes — probablement négligeable. |
pressure |
5 % | Quelques manques, mais encore gérable par imputation simple. |
triceps |
30 % | Taux de valeurs manquantes élevé. Cela peut influencer les analyses statistiques. |
insulin |
49 % | Presque la moitié des données manquent — problématique pour les analyses multivariées. |
mass |
1 % | Très faible proportion de manquants. |
pedigree, age, diabetes |
0 % | Données complètes. |
L’analyse des valeurs manquantes montre que les variables insulin (49 %) et triceps (30 %) présentent des taux de données manquantes élevés, ce qui pourrait biaiser les analyses statistiques si ces valeurs ne sont pas imputées. Les autres variables présentent des taux de manquants inférieurs à 5 %, considérés comme acceptables pour les traitements classiques.
L’analyse des distributions permet de mieux comprendre la structure des données, d’identifier les asymétries, les valeurs extrêmes, et de guider les choix de transformation ou de modélisation. Voici une visualisation des variables cliniques disponibles dans la base.
library(mlbench)
library(tidyverse)
data(PimaIndiansDiabetes2)
df <- PimaIndiansDiabetes2
# Visualisation des distributions (hors variable cible)
df %>%
select(-diabetes) %>%
gather(variable, value) %>%
ggplot(aes(x = value)) +
geom_histogram(bins = 30, fill = "steelblue", color = "white") +
facet_wrap(~variable, scales = "free") +
labs(title = "Distribution des variables cliniques",
x = "Valeur",
y = "Fréquence") +
theme_minimal(base_size = 14)
## Warning: Removed 652 rows containing non-finite outside the scale range
## (`stat_bin()`).
Interprétation
Certaines variables comme glucose, mass et age présentent des distributions asymétriques, ce qui pourrait nécessiter une transformation (logarithmique ou normalisation).Les variables triceps et insulin montrent des concentrations autour de zéro, probablement dues aux valeurs manquantes ou mal enregistrées.La variable pregnant est discrète, avec une majorité de patientes ayant eu peu ou pas de grossesses.
##Comparaison selon le statut diabétique
df %>%
gather(variable, value, -diabetes) %>%
ggplot(aes(x = value, fill = diabetes)) +
geom_density(alpha = 0.5) +
facet_wrap(~variable, scales = "free") +
labs(title = "Distributions selon le statut diabétique",
x = "Valeur",
y = "Densité") +
scale_fill_manual(values = c("dodgerblue", "firebrick"),
name = "Diabète",
labels = c("Non diabétique", "Diabétique")) +
theme_minimal(base_size = 14)
## Warning: Removed 652 rows containing non-finite outside the scale range
## (`stat_density()`).
Nous observons de plus que les patientes diabétiques tendent à avoir des
niveaux de glucose et d’IMC plus élevés.La fonction génétique (pedigree)
semble légèrement plus concentrée chez les diabétiques. Ces différences
justifient l’utilisation de ces variables comme prédicteurs dans un
modèle supervisé.
Pour identifier les variables les plus informatives dans la
prédiction du diabète, nous évaluons la corrélation entre chaque
variable numérique et la variable cible diabetes. Comme
diabetes est une variable binaire, nous utilisons des tests
adaptés : corrélation de point bisérial ou comparaison des moyennes.
##Corrélation entre les variables cliniques et la cible diabetes
library(mlbench)
library(tidyverse)
library(corrplot)
## Warning: le package 'corrplot' a été compilé avec la version R 4.4.3
## corrplot 0.95 loaded
# Conversion de la variable cible en numérique (0 = neg, 1 = pos)
df$diabetes_num <- ifelse(df$diabetes == "pos", 1, 0)
# Sélection des variables numériques
num_vars <- df %>% select(-diabetes, -diabetes_num) %>% select_if(is.numeric)
# Calcul des corrélations avec la cible
correlations <- sapply(num_vars, function(x) cor(x, df$diabetes_num, use = "complete.obs"))
# Affichage sous forme de tableau
cor_df <- data.frame(Variable = names(correlations), Correlation = round(correlations, 3))
cor_df %>% arrange(desc(abs(Correlation)))
## Variable Correlation
## glucose glucose 0.495
## mass mass 0.314
## insulin insulin 0.303
## triceps triceps 0.259
## age age 0.238
## pregnant pregnant 0.222
## pedigree pedigree 0.174
## pressure pressure 0.171
##Interprétation stratégique de la corrélation
| Variable | Corrélation avec diabetes | Taux de valeurs manquantes | Décision recommandée |
|---|---|---|---|
| glucose | 0.495 (forte) | Faible | ✅ Imputer par médiane |
| mass | 0.314 (modérée) | Faible | ✅ Imputer par médiane |
| insulin | 0.303 (modérée) | Élevé (49%) | ⚠️ Imputer avec MICE ou tester sans |
| triceps | 0.259 (modérée) | Modéré (30%) | ✅ Imputer avec KNN ou MICE |
| age | 0.238 (modérée) | Aucun | ✅ Utiliser directement |
| pregnant | 0.222 (modérée) | Faible | ✅ Imputer par médiane |
| pedigree | 0.174 (faible) | Aucun | ✅ Utiliser directement |
| pressure | 0.171 (faible) | Faible | ✅ Imputer par médiane |
##Traitement des valeurs manquantes
library(mlbench)
library(mice)
## Warning: le package 'mice' a été compilé avec la version R 4.4.3
##
## Attachement du package : 'mice'
## L'objet suivant est masqué depuis 'package:stats':
##
## filter
## Les objets suivants sont masqués depuis 'package:base':
##
## cbind, rbind
library(VIM)
## Warning: le package 'VIM' a été compilé avec la version R 4.4.3
## Le chargement a nécessité le package : colorspace
## Le chargement a nécessité le package : grid
## VIM is ready to use.
## Suggestions and bug-reports can be submitted at: https://github.com/statistikat/VIM/issues
##
## Attachement du package : 'VIM'
## L'objet suivant est masqué depuis 'package:datasets':
##
## sleep
library(tidyverse)
# Chargement des données
data(PimaIndiansDiabetes2)
df <- PimaIndiansDiabetes2
# Étape 1 : Imputation par médiane
median_vars <- c("pregnant", "pressure", "mass", "glucose")
for (var in median_vars) {
df[[var]][is.na(df[[var]])] <- median(df[[var]], na.rm = TRUE)
}
# Étape 2 : Imputation par KNN pour triceps
df_knn <- kNN(df, variable = "triceps", k = 5, imp_var = FALSE)
## pregnant glucose pressure insulin mass pedigree age pregnant
## 0.000 44.000 24.000 14.000 18.200 0.078 21.000 17.000
## glucose pressure insulin mass pedigree age
## 199.000 122.000 846.000 67.100 2.420 81.000
# Étape 3 : Imputation par MICE pour insulin
# On applique MICE uniquement sur insulin, en utilisant les autres variables comme prédicteurs
mice_input <- df_knn %>% select(insulin, glucose, mass, age, pregnant, pressure, triceps, diabetes)
mice_result <- mice(mice_input, method = "rf", m = 5, seed = 123)
##
## iter imp variable
## 1 1 insulin
## 1 2 insulin
## 1 3 insulin
## 1 4 insulin
## 1 5 insulin
## 2 1 insulin
## 2 2 insulin
## 2 3 insulin
## 2 4 insulin
## 2 5 insulin
## 3 1 insulin
## 3 2 insulin
## 3 3 insulin
## 3 4 insulin
## 3 5 insulin
## 4 1 insulin
## 4 2 insulin
## 4 3 insulin
## 4 4 insulin
## 4 5 insulin
## 5 1 insulin
## 5 2 insulin
## 5 3 insulin
## 5 4 insulin
## 5 5 insulin
# Remplacement de la variable insulin imputée
df_knn$insulin <- complete(mice_result)$insulin
# Résultat final
df_final <- df_knn
# Vérification
summary(df_final)
## pregnant glucose pressure triceps
## Min. : 0.000 Min. : 44.00 Min. : 24.00 Min. : 7.00
## 1st Qu.: 1.000 1st Qu.: 99.75 1st Qu.: 64.00 1st Qu.:23.00
## Median : 3.000 Median :117.00 Median : 72.00 Median :30.00
## Mean : 3.845 Mean :121.66 Mean : 72.39 Mean :29.25
## 3rd Qu.: 6.000 3rd Qu.:140.25 3rd Qu.: 80.00 3rd Qu.:35.00
## Max. :17.000 Max. :199.00 Max. :122.00 Max. :99.00
## insulin mass pedigree age diabetes
## Min. : 14.0 Min. :18.20 Min. :0.0780 Min. :21.00 neg:500
## 1st Qu.: 76.0 1st Qu.:27.50 1st Qu.:0.2437 1st Qu.:24.00 pos:268
## Median :125.0 Median :32.30 Median :0.3725 Median :29.00
## Mean :156.1 Mean :32.46 Mean :0.4719 Mean :33.24
## 3rd Qu.:188.5 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :846.0 Max. :67.10 Max. :2.4200 Max. :81.00
##pour prédire la probabilité d’etre diabétique en fonction de plusieurs variables cliniques. ## Deux échantillons : 80% en apprentissage et 20% en test.
sample_n(df_final, 3)
## pregnant glucose pressure triceps insulin mass pedigree age diabetes
## 1 1 117 60 23 106 33.8 0.466 27 neg
## 2 6 154 78 41 140 46.1 0.571 27 neg
## 3 2 83 66 23 50 32.2 0.497 22 neg
library(caret)
## Warning: le package 'caret' a été compilé avec la version R 4.4.2
## Le chargement a nécessité le package : lattice
##
## Attachement du package : 'caret'
## L'objet suivant est masqué depuis 'package:purrr':
##
## lift
set.seed(123)
training.samples <- df_final$diabetes %>%
createDataPartition(p = 0.8, list = FALSE)
train.data <- df_final[training.samples, ]
test.data <- df_final[-training.samples, ]
##Créons la matrice des prédicteurs
x <- model.matrix(diabetes~., train.data)[,-1]
y <- ifelse(train.data$diabetes == "pos", 1, 0)
##Justification du choix de la régression Lasso
Dans le cadre de notre étude visant à prédire la probabilité d’être diabétique à partir de variables cliniques, nous avons appliqué un traitement rigoureux des données manquantes, suivi d’une analyse exploratoire des distributions et des corrélations. Ce processus a révélé que certaines variables (comme glucose, mass, insulin, triceps) présentent une corrélation modérée à forte avec le statut diabétique, tandis que d’autres sont moins informatives.
Compte tenu de cette hétérogénéité, la régression Lasso s’est imposée comme une méthode particulièrement adaptée pour les raisons suivantes :
Sélection automatique de variables : Lasso applique une pénalisation L1 qui permet d’éliminer les variables peu contributives en mettant leurs coefficients à zéro. Cela favorise un modèle plus parcimonieux et interprétable.
Réduction du surajustement : En limitant la complexité du modèle, Lasso améliore la généralisation sur de nouvelles données, ce qui est essentiel dans un contexte clinique.
Robustesse après imputation : Notre pipeline d’imputation (médiane, KNN, MICE) a permis de reconstituer un jeu de données complet. Lasso est compatible avec ce type de données et permet de tester la pertinence des variables imputées.
Alignement avec l’objectif prédictif : Le modèle Lasso, intégré dans une régression logistique pénalisée, permet d’estimer la probabilité d’être diabétique tout en optimisant la sélection des prédicteurs.
library(glmnet)
## Warning: le package 'glmnet' a été compilé avec la version R 4.4.2
## Le chargement a nécessité le package : Matrix
##
## Attachement du package : 'Matrix'
## Les objets suivants sont masqués depuis 'package:tidyr':
##
## expand, pack, unpack
## Loaded glmnet 4.1-8
lasso <- glmnet(x, y, family = "binomial", alpha = 1, lambda = NULL)
plot(lasso)
set.seed(123)
cv.lasso <- cv.glmnet(x, y, alpha = 1, family = "binomial")
str(cv.lasso)
## List of 12
## $ lambda : num [1:59] 0.232 0.211 0.192 0.175 0.16 ...
## $ cvm : num [1:59] 1.29 1.26 1.23 1.2 1.18 ...
## $ cvsd : num [1:59] 0.0225 0.0234 0.0228 0.0229 0.0233 ...
## $ cvup : num [1:59] 1.32 1.28 1.25 1.22 1.2 ...
## $ cvlo : num [1:59] 1.27 1.24 1.2 1.18 1.15 ...
## $ nzero : Named int [1:59] 0 1 1 1 1 1 1 1 2 2 ...
## ..- attr(*, "names")= chr [1:59] "s0" "s1" "s2" "s3" ...
## $ call : language cv.glmnet(x = x, y = y, alpha = 1, family = "binomial")
## $ name : Named chr "Binomial Deviance"
## ..- attr(*, "names")= chr "deviance"
## $ glmnet.fit:List of 13
## ..$ a0 : Named num [1:59] -0.621 -0.984 -1.316 -1.621 -1.904 ...
## .. ..- attr(*, "names")= chr [1:59] "s0" "s1" "s2" "s3" ...
## ..$ beta :Formal class 'dgCMatrix' [package "Matrix"] with 6 slots
## .. .. ..@ i : int [1:334] 1 1 1 1 1 1 1 1 5 1 ...
## .. .. ..@ p : int [1:60] 0 0 1 2 3 4 5 6 7 9 ...
## .. .. ..@ Dim : int [1:2] 8 59
## .. .. ..@ Dimnames:List of 2
## .. .. .. ..$ : chr [1:8] "pregnant" "glucose" "pressure" "triceps" ...
## .. .. .. ..$ : chr [1:59] "s0" "s1" "s2" "s3" ...
## .. .. ..@ x : num [1:334] 0.00297 0.00566 0.00813 0.01041 0.01252 ...
## .. .. ..@ factors : list()
## ..$ df : int [1:59] 0 1 1 1 1 1 1 1 2 2 ...
## ..$ dim : int [1:2] 8 59
## ..$ lambda : num [1:59] 0.232 0.211 0.192 0.175 0.16 ...
## ..$ dev.ratio : num [1:59] -6.18e-15 3.08e-02 5.63e-02 7.75e-02 9.54e-02 ...
## ..$ nulldev : num 796
## ..$ npasses : int 364
## ..$ jerr : int 0
## ..$ offset : logi FALSE
## ..$ classnames: chr [1:2] "0" "1"
## ..$ call : language glmnet(x = x, y = y, alpha = 1, family = "binomial")
## ..$ nobs : int 615
## ..- attr(*, "class")= chr [1:2] "lognet" "glmnet"
## $ lambda.min: num 0.00321
## $ lambda.1se: num 0.0476
## $ index : int [1:2, 1] 47 18
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : chr [1:2] "min" "1se"
## .. ..$ : chr "Lambda"
## - attr(*, "class")= chr "cv.glmnet"
model <- glmnet(x, y, alpha = 1, family = "binomial",
lambda = cv.lasso$lambda.min)
str(model)
## List of 13
## $ a0 : Named num -8.38
## ..- attr(*, "names")= chr "s0"
## $ beta :Formal class 'dgCMatrix' [package "Matrix"] with 6 slots
## .. ..@ i : int [1:8] 0 1 2 3 4 5 6 7
## .. ..@ p : int [1:2] 0 8
## .. ..@ Dim : int [1:2] 8 1
## .. ..@ Dimnames:List of 2
## .. .. ..$ : chr [1:8] "pregnant" "glucose" "pressure" "triceps" ...
## .. .. ..$ : chr "s0"
## .. ..@ x : num [1:8] 0.094856 0.034971 -0.006537 0.014832 0.000129 ...
## .. ..@ factors : list()
## $ df : int 8
## $ dim : int [1:2] 8 1
## $ lambda : num 0.00321
## $ dev.ratio : num 0.262
## $ nulldev : num 796
## $ npasses : int 30
## $ jerr : int 0
## $ offset : logi FALSE
## $ classnames: chr [1:2] "0" "1"
## $ call : language glmnet(x = x, y = y, family = "binomial", alpha = 1, lambda = cv.lasso$lambda.min)
## $ nobs : int 615
## - attr(*, "class")= chr [1:2] "lognet" "glmnet"
coef(model)
## 9 x 1 sparse Matrix of class "dgCMatrix"
## s0
## (Intercept) -8.3751350342
## pregnant 0.0948555492
## glucose 0.0349713795
## pressure -0.0065374804
## triceps 0.0148321673
## insulin 0.0001293714
## mass 0.0685062734
## pedigree 0.7843532950
## age 0.0104174307
x.test <- model.matrix(diabetes ~., test.data)[,-1]
x.test
## pregnant glucose pressure triceps insulin mass pedigree age
## 2 1 85 66 29 43 26.6 0.351 31
## 5 0 137 40 35 168 43.1 2.288 33
## 17 0 118 84 47 230 45.8 0.551 31
## 25 11 143 94 33 146 36.6 0.254 51
## 27 7 147 76 32 125 39.4 0.257 43
## 34 6 92 92 27 110 19.9 0.188 28
## 36 4 103 60 33 192 24.0 0.966 33
## 41 3 180 64 25 70 34.0 0.271 26
## 53 5 88 66 21 23 24.4 0.342 30
## 54 8 176 90 34 300 33.7 0.467 58
## 57 7 187 68 39 304 37.7 0.254 41
## 66 5 99 74 27 50 29.0 0.203 32
## 67 0 109 88 30 74 32.5 0.855 38
## 68 2 109 92 30 105 42.7 0.845 54
## 71 2 100 66 20 90 32.9 0.867 28
## 76 1 117 48 20 291 24.7 0.140 22
## 78 5 95 72 33 77 37.7 0.370 27
## 80 2 112 66 22 176 25.0 0.307 24
## 82 2 74 72 28 40 32.3 0.102 22
## 85 5 137 108 36 160 48.8 0.227 37
## 91 1 80 55 15 105 19.1 0.258 21
## 93 7 81 78 40 48 46.7 0.261 42
## 96 6 144 72 27 228 33.9 0.255 40
## 98 1 71 48 18 76 20.4 0.323 22
## 103 0 125 96 22 105 22.5 0.262 21
## 106 1 126 56 29 152 28.7 0.801 21
## 109 3 83 58 31 18 34.3 0.336 25
## 115 7 160 54 32 175 30.5 0.588 39
## 117 5 124 74 30 126 34.0 0.220 38
## 124 5 132 80 26 22 26.8 0.186 69
## 131 4 173 70 14 168 29.7 0.361 33
## 132 9 122 56 31 342 33.3 1.114 33
## 140 5 105 72 29 325 36.9 0.159 28
## 148 2 106 64 35 119 30.5 1.400 34
## 152 4 114 65 24 125 21.9 0.432 37
## 156 7 152 88 44 545 50.0 0.337 36
## 157 2 99 52 15 94 24.6 0.637 21
## 165 0 131 88 30 180 31.6 0.743 32
## 175 2 75 64 24 55 29.7 0.370 33
## 176 8 179 72 42 130 32.7 0.719 36
## 190 5 139 80 35 160 31.6 0.361 25
## 192 9 123 70 44 94 33.1 0.374 40
## 195 8 85 55 20 49 24.4 0.136 42
## 201 0 113 80 16 183 31.0 0.874 21
## 206 5 111 72 28 68 23.9 0.407 27
## 209 1 96 64 27 87 33.2 0.289 21
## 217 5 109 62 41 129 35.8 0.514 25
## 225 1 100 66 15 56 23.6 0.666 26
## 229 4 197 70 39 744 36.7 2.329 31
## 232 6 134 80 37 370 46.2 0.238 46
## 233 1 79 80 25 37 25.4 0.583 22
## 239 9 164 84 21 132 30.8 0.831 32
## 240 0 104 76 20 68 18.4 0.582 27
## 242 4 91 70 32 88 33.1 0.446 22
## 246 9 184 85 15 144 30.0 1.213 49
## 256 1 113 64 35 96 33.6 0.543 21
## 261 3 191 68 15 130 30.9 0.299 34
## 265 4 123 62 29 190 32.0 0.226 35
## 269 0 102 52 20 63 25.1 0.078 21
## 273 3 122 78 36 110 23.0 0.254 40
## 280 2 108 62 10 278 25.3 0.881 22
## 284 7 161 86 32 285 30.4 0.165 47
## 289 4 96 56 17 49 20.8 0.340 26
## 290 5 108 72 43 75 36.1 0.263 33
## 295 0 161 50 20 140 21.9 0.254 65
## 297 2 146 70 38 360 28.0 0.337 29
## 299 14 100 78 25 184 36.6 0.412 46
## 314 3 113 50 10 85 29.5 0.626 25
## 324 13 152 90 33 29 26.8 0.731 43
## 332 2 87 58 16 52 32.7 0.166 25
## 334 12 106 80 31 128 23.6 0.137 44
## 340 7 178 84 32 155 39.9 0.331 41
## 371 3 173 82 48 465 38.4 2.137 25
## 374 2 105 58 40 94 34.9 0.225 25
## 377 0 98 82 15 84 25.2 0.299 22
## 379 4 156 75 36 120 48.3 0.238 32
## 382 0 105 68 22 82 20.0 0.236 22
## 384 1 90 62 18 59 25.1 1.268 25
## 388 8 105 100 36 155 43.3 0.239 45
## 392 5 166 76 36 321 45.7 0.340 27
## 396 2 127 58 24 275 27.7 1.600 25
## 399 3 82 70 22 87 21.1 0.389 25
## 421 1 119 88 41 170 45.3 0.507 26
## 438 5 147 75 27 193 29.9 0.434 28
## 442 2 83 66 23 50 32.2 0.497 22
## 444 8 108 70 31 168 30.5 0.955 33
## 447 1 100 72 12 70 25.3 0.658 28
## 452 2 134 70 30 250 28.9 0.542 23
## 476 0 137 84 27 148 27.3 0.231 59
## 477 2 105 80 45 191 33.7 0.711 29
## 480 4 132 86 31 330 28.0 0.419 63
## 492 2 89 90 30 108 33.5 0.292 42
## 498 2 81 72 15 76 30.1 0.547 25
## 499 7 195 70 33 145 25.1 0.163 55
## 509 2 84 50 23 76 30.4 0.968 21
## 517 9 145 88 34 165 30.3 0.771 53
## 521 2 68 70 32 66 25.0 0.187 25
## 523 6 114 72 28 120 32.3 0.189 26
## 525 3 125 58 24 275 31.6 0.151 24
## 526 3 87 60 18 76 21.8 0.444 21
## 533 1 86 66 52 65 41.3 0.917 29
## 538 0 57 60 20 600 21.7 0.735 67
## 546 8 186 90 35 225 34.5 0.423 37
## 547 5 187 76 27 207 43.6 1.034 53
## 549 1 164 82 43 67 32.8 0.341 50
## 555 1 84 64 23 115 36.9 0.471 28
## 560 11 85 74 27 94 30.1 0.300 35
## 575 1 143 86 30 330 30.1 0.892 23
## 577 6 108 44 20 130 24.0 0.813 35
## 578 2 118 80 35 120 42.9 0.693 21
## 588 6 103 66 27 215 24.3 0.249 29
## 591 11 111 84 40 215 46.8 0.925 45
## 592 2 112 78 50 140 39.4 0.175 24
## 605 4 183 72 31 56 28.4 0.212 36
## 609 0 152 82 39 272 41.5 0.270 27
## 615 11 138 74 26 144 36.1 0.557 50
## 619 9 112 82 24 175 28.2 1.282 50
## 622 2 92 76 20 49 24.2 1.698 28
## 624 0 94 70 27 115 43.5 0.347 21
## 628 0 132 78 26 275 32.4 0.393 21
## 633 2 111 60 23 56 26.2 0.343 23
## 635 10 92 62 27 23 25.9 0.167 31
## 637 5 104 74 30 275 28.8 0.153 48
## 642 4 128 70 32 88 34.3 0.303 24
## 648 0 179 50 36 159 37.8 0.455 22
## 649 11 136 84 35 130 28.3 0.260 42
## 650 0 107 60 25 192 26.4 0.133 23
## 655 1 106 70 28 135 34.2 0.142 22
## 659 11 127 106 33 140 39.0 0.190 51
## 661 10 162 84 31 60 27.7 0.182 54
## 663 8 167 106 46 231 37.6 0.165 43
## 674 3 123 100 35 240 57.3 0.880 22
## 678 0 93 60 31 100 35.3 0.263 25
## 683 0 95 64 39 105 44.6 0.366 22
## 687 3 130 64 22 170 23.1 0.314 22
## 694 7 129 68 49 125 38.5 0.439 43
## 701 2 122 76 27 200 35.9 0.483 26
## 704 2 129 72 39 194 38.5 0.304 41
## 705 4 110 76 20 100 28.4 0.118 27
## 713 10 129 62 36 130 41.2 0.441 38
## 715 3 102 74 27 71 29.5 0.121 32
## 719 1 108 60 46 178 35.5 0.415 24
## 720 5 97 76 27 207 35.6 0.378 52
## 736 4 95 60 32 49 35.4 0.284 28
## 737 0 126 86 27 120 27.4 0.515 21
## 740 1 102 74 32 215 39.5 0.293 42
## 746 12 100 84 33 105 30.0 0.488 46
## 753 3 108 62 24 105 26.0 0.223 25
## 762 9 170 74 31 126 44.0 0.403 43
## 765 2 122 70 27 95 36.8 0.340 27
## 766 5 121 72 23 112 26.2 0.245 30
## 767 1 126 60 31 175 30.1 0.349 47
## 768 1 93 70 31 106 30.4 0.315 23
proba <- model %>% predict(newx = x.test)
str(proba)
## num [1:153, 1] -2.883 1.786 -0.178 0.801 0.772 ...
## - attr(*, "dimnames")=List of 2
## ..$ : chr [1:153] "2" "5" "17" "25" ...
## ..$ : chr "s0"
predicted.classes <- ifelse(proba > 0.5, "pos", "neg")
observed.classes <- test.data$diabetes
mean(predicted.classes == observed.classes)
## [1] 0.8104575
set.seed(123)
cv.lasso <- cv.glmnet(x, y, alpha = 1, family = "binomial")
plot(cv.lasso)
cv.lasso <- cv.glmnet(x, y, alpha = 1, family = "binomial")
plot(cv.lasso)
## Fonction de perte : erreur de classification
cv.lasso <- cv.glmnet(x, y, alpha = 1, family = "binomial", type.measure="class")
plot(cv.lasso)
Ce graphique montre comment le modèle choisit les variables les plus
utiles pour prédire le diabète. On teste différents niveaux de
complexité, et à chaque étape, le modèle garde ou élimine certaines
variables.
✅ Ce que ça implique concrètement :
Quand la régularisation est faible (à gauche du graphique), le modèle utilise presque toutes les variables. Il est plus précis, mais risque de trop s’adapter aux données (surajustement).
Quand la régularisation est forte (à droite), le modèle devient très simple : il garde 1 ou 2 variables seulement, mais perd en précision (sous-ajustement).
Le meilleur compromis se trouve au centre : le modèle garde environ 6 variables qui sont vraiment utiles pour prédire si une personne est diabétique, tout en restant stable et fiable.
cv.lasso <- cv.glmnet(x, y, alpha = 1, family = "binomial", type.measure="auc")
plot(cv.lasso)
str(cv.lasso)
## List of 12
## $ lambda : num [1:59] 0.232 0.211 0.192 0.175 0.16 ...
## $ cvm : num [1:59] 0.65 0.784 0.784 0.784 0.784 ...
## $ cvsd : num [1:59] 0.0412 0.0151 0.0151 0.0151 0.0151 ...
## $ cvup : num [1:59] 0.691 0.799 0.799 0.799 0.799 ...
## $ cvlo : num [1:59] 0.608 0.769 0.769 0.769 0.769 ...
## $ nzero : Named int [1:59] 0 1 1 1 1 1 1 1 2 2 ...
## ..- attr(*, "names")= chr [1:59] "s0" "s1" "s2" "s3" ...
## $ call : language cv.glmnet(x = x, y = y, type.measure = "auc", alpha = 1, family = "binomial")
## $ name : Named chr "AUC"
## ..- attr(*, "names")= chr "auc"
## $ glmnet.fit:List of 13
## ..$ a0 : Named num [1:59] -0.621 -0.984 -1.316 -1.621 -1.904 ...
## .. ..- attr(*, "names")= chr [1:59] "s0" "s1" "s2" "s3" ...
## ..$ beta :Formal class 'dgCMatrix' [package "Matrix"] with 6 slots
## .. .. ..@ i : int [1:334] 1 1 1 1 1 1 1 1 5 1 ...
## .. .. ..@ p : int [1:60] 0 0 1 2 3 4 5 6 7 9 ...
## .. .. ..@ Dim : int [1:2] 8 59
## .. .. ..@ Dimnames:List of 2
## .. .. .. ..$ : chr [1:8] "pregnant" "glucose" "pressure" "triceps" ...
## .. .. .. ..$ : chr [1:59] "s0" "s1" "s2" "s3" ...
## .. .. ..@ x : num [1:334] 0.00297 0.00566 0.00813 0.01041 0.01252 ...
## .. .. ..@ factors : list()
## ..$ df : int [1:59] 0 1 1 1 1 1 1 1 2 2 ...
## ..$ dim : int [1:2] 8 59
## ..$ lambda : num [1:59] 0.232 0.211 0.192 0.175 0.16 ...
## ..$ dev.ratio : num [1:59] -6.18e-15 3.08e-02 5.63e-02 7.75e-02 9.54e-02 ...
## ..$ nulldev : num 796
## ..$ npasses : int 364
## ..$ jerr : int 0
## ..$ offset : logi FALSE
## ..$ classnames: chr [1:2] "0" "1"
## ..$ call : language glmnet(x = x, y = y, alpha = 1, family = "binomial")
## ..$ nobs : int 615
## ..- attr(*, "class")= chr [1:2] "lognet" "glmnet"
## $ lambda.min: num 0.0098
## $ lambda.1se: num 0.0691
## $ index : int [1:2, 1] 35 14
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : chr [1:2] "min" "1se"
## .. ..$ : chr "Lambda"
## - attr(*, "class")= chr "cv.glmnet"
cv.lasso$lambda.min
## [1] 0.009795309
##Interpretation Ce graphique nous aide à choisir le meilleur modèle pour prédire si une personne est diabétique, en testant différents niveaux de complexité.
Chaque point rouge représente la performance du modèle pour une valeur donnée du paramètre de régularisation λ (lambda).
Plus l’AUC est élevé, meilleur est le modèle pour distinguer les personnes diabétiques des non-diabétiques.
Les barres grises montrent l’incertitude (la variabilité) autour de chaque point.
Ce que ça signifie pour les variables En haut du graphique, les chiffres indiquent combien de variables sont utilisées dans le modèle à chaque niveau de régularisation.
Quand λ est petit (à gauche), le modèle utilise presque toutes les variables → il est plus précis mais peut être trop complexe.
Quand λ est grand (à droite), le modèle devient très simple → il utilise 1 ou 2 variables seulement, mais la performance diminue.
Le meilleur compromis se trouve au centre : le modèle utilise environ 6 variables et atteint une AUC proche de 0.83, ce qui est très bon.
En résuméé, Ce raphique montre que notre modèle Lasso a réussi à filtrer les variables cliniques les plus utiles pour prédire le diabète. Il garde les plus pertinentes (comme le glucose, la masse corporelle, etc.) et ignore celles qui n’apportent pas grand-chose, pour construire un modèle simple, efficace et fiable
cette fonction produit deux lambda optimal lambda.min correspondant à la valeur qui minimise l’erreur de prédiction de la cross-’validation lambda.1SE correspond à la plus grande valeur de lambda equivalent à l’erreur de prédiction + 1 ecart type C’est le lambda qui donne un modèle parcimonieux: Moins de variable avec la méme précision
cv.lasso$lambda.1se
## [1] 0.06910397
##sortie des coefficient pour les deux lambda optimaux
coef(cv.lasso, cv.lasso$lambda.min)
## 9 x 1 sparse Matrix of class "dgCMatrix"
## s1
## (Intercept) -8.073314e+00
## pregnant 8.269018e-02
## glucose 3.332336e-02
## pressure .
## triceps 1.241029e-02
## insulin 3.353037e-05
## mass 6.058467e-02
## pedigree 6.572459e-01
## age 7.380311e-03
coef(cv.lasso, cv.lasso$lambda.1se)
## 9 x 1 sparse Matrix of class "dgCMatrix"
## s1
## (Intercept) -4.417692432
## pregnant 0.002429418
## glucose 0.023838524
## pressure .
## triceps .
## insulin .
## mass 0.024895334
## pedigree .
## age .
coeff <- cbind(coef(cv.lasso, cv.lasso$lambda.min),coef(cv.lasso, cv.lasso$lambda.1se))
coeff
## 9 x 2 sparse Matrix of class "dgCMatrix"
## s1 s1
## (Intercept) -8.073314e+00 -4.417692432
## pregnant 8.269018e-02 0.002429418
## glucose 3.332336e-02 0.023838524
## pressure . .
## triceps 1.241029e-02 .
## insulin 3.353037e-05 .
## mass 6.058467e-02 0.024895334
## pedigree 6.572459e-01 .
## age 7.380311e-03 .
lasso.model <- glmnet(x, y, alpha = 1, family = "binomial",
lambda = cv.lasso$lambda.min)
x.test <- model.matrix(diabetes ~., test.data)[,-1]
probabilities <- lasso.model %>% predict(newx = x.test)
predicted.classes <- ifelse(probabilities > 0.5, "pos", "neg")
observed.classes <- test.data$diabetes
mean(predicted.classes == observed.classes)
## [1] 0.8039216
lasso.model <- glmnet(x, y, alpha = 1, family = "binomial",
lambda = cv.lasso$lambda.1se)
x.test <- model.matrix(diabetes ~., test.data)[,-1]
probabilities <- lasso.model %>% predict(newx = x.test)
predicted.classes <- ifelse(probabilities > 0.5, "pos", "neg")
observed.classes <- test.data$diabetes
mean(predicted.classes == observed.classes)
## [1] 0.7320261
full.model <- glm(diabetes ~., data = train.data, family = binomial)
str(full.model)
## List of 30
## $ coefficients : Named num [1:9] -8.5406 0.1013 0.0359 -0.01 0.0161 ...
## ..- attr(*, "names")= chr [1:9] "(Intercept)" "pregnant" "glucose" "pressure" ...
## $ residuals : Named num [1:615] 1.44 1.26 -1.05 -1.17 14.85 ...
## ..- attr(*, "names")= chr [1:615] "1" "3" "4" "6" ...
## $ fitted.values : Named num [1:615] 0.6959 0.7911 0.0439 0.1462 0.0673 ...
## ..- attr(*, "names")= chr [1:615] "1" "3" "4" "6" ...
## $ effects : Named num [1:615] 4.967 -2.77 9.453 -0.446 -3.858 ...
## ..- attr(*, "names")= chr [1:615] "(Intercept)" "pregnant" "glucose" "pressure" ...
## $ R : num [1:9, 1:9] -9.79 0 0 0 0 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : chr [1:9] "(Intercept)" "pregnant" "glucose" "pressure" ...
## .. ..$ : chr [1:9] "(Intercept)" "pregnant" "glucose" "pressure" ...
## $ rank : int 9
## $ qr :List of 5
## ..$ qr : num [1:615, 1:9] -9.7926 0.0415 0.0209 0.0361 0.0256 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : chr [1:615] "1" "3" "4" "6" ...
## .. .. ..$ : chr [1:9] "(Intercept)" "pregnant" "glucose" "pressure" ...
## ..$ rank : int 9
## ..$ qraux: num [1:9] 1.05 1.05 1.03 1 1.01 ...
## ..$ pivot: int [1:9] 1 2 3 4 5 6 7 8 9
## ..$ tol : num 1e-11
## ..- attr(*, "class")= chr "qr"
## $ family :List of 13
## ..$ family : chr "binomial"
## ..$ link : chr "logit"
## ..$ linkfun :function (mu)
## ..$ linkinv :function (eta)
## ..$ variance :function (mu)
## ..$ dev.resids:function (y, mu, wt)
## ..$ aic :function (y, n, mu, wt, dev)
## ..$ mu.eta :function (eta)
## ..$ initialize: language { if (NCOL(y) == 1) { ...
## ..$ validmu :function (mu)
## ..$ valideta :function (eta)
## ..$ simulate :function (object, nsim)
## ..$ dispersion: num 1
## ..- attr(*, "class")= chr "family"
## $ linear.predictors: Named num [1:615] 0.828 1.332 -3.081 -1.765 -2.629 ...
## ..- attr(*, "names")= chr [1:615] "1" "3" "4" "6" ...
## $ deviance : num 587
## $ aic : num 605
## $ null.deviance : num 796
## $ iter : int 5
## $ weights : Named num [1:615] 0.2116 0.1653 0.042 0.1248 0.0628 ...
## ..- attr(*, "names")= chr [1:615] "1" "3" "4" "6" ...
## $ prior.weights : Named num [1:615] 1 1 1 1 1 1 1 1 1 1 ...
## ..- attr(*, "names")= chr [1:615] "1" "3" "4" "6" ...
## $ df.residual : int 606
## $ df.null : int 614
## $ y : Named num [1:615] 1 1 0 0 1 0 1 1 0 1 ...
## ..- attr(*, "names")= chr [1:615] "1" "3" "4" "6" ...
## $ converged : logi TRUE
## $ boundary : logi FALSE
## $ model :'data.frame': 615 obs. of 9 variables:
## ..$ diabetes: Factor w/ 2 levels "neg","pos": 2 2 1 1 2 1 2 2 1 2 ...
## ..$ pregnant: num [1:615] 6 8 1 5 3 10 2 8 4 10 ...
## ..$ glucose : num [1:615] 148 183 89 116 78 115 197 125 110 168 ...
## ..$ pressure: num [1:615] 72 64 66 74 50 72 70 96 92 74 ...
## ..$ triceps : num [1:615] 35 28 23 27 32 39 45 32 38 32 ...
## ..$ insulin : num [1:615] 155 180 94 105 88 75 543 300 235 207 ...
## ..$ mass : num [1:615] 33.6 23.3 28.1 25.6 31 35.3 30.5 32.3 37.6 38 ...
## ..$ pedigree: num [1:615] 0.627 0.672 0.167 0.201 0.248 0.134 0.158 0.232 0.191 0.537 ...
## ..$ age : num [1:615] 50 32 21 30 26 29 53 54 30 34 ...
## ..- attr(*, "terms")=Classes 'terms', 'formula' language diabetes ~ pregnant + glucose + pressure + triceps + insulin + mass + pedigree + age
## .. .. ..- attr(*, "variables")= language list(diabetes, pregnant, glucose, pressure, triceps, insulin, mass, pedigree, age)
## .. .. ..- attr(*, "factors")= int [1:9, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
## .. .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. .. ..$ : chr [1:9] "diabetes" "pregnant" "glucose" "pressure" ...
## .. .. .. .. ..$ : chr [1:8] "pregnant" "glucose" "pressure" "triceps" ...
## .. .. ..- attr(*, "term.labels")= chr [1:8] "pregnant" "glucose" "pressure" "triceps" ...
## .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
## .. .. ..- attr(*, "intercept")= int 1
## .. .. ..- attr(*, "response")= int 1
## .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
## .. .. ..- attr(*, "predvars")= language list(diabetes, pregnant, glucose, pressure, triceps, insulin, mass, pedigree, age)
## .. .. ..- attr(*, "dataClasses")= Named chr [1:9] "factor" "numeric" "numeric" "numeric" ...
## .. .. .. ..- attr(*, "names")= chr [1:9] "diabetes" "pregnant" "glucose" "pressure" ...
## $ call : language glm(formula = diabetes ~ ., family = binomial, data = train.data)
## $ formula :Class 'formula' language diabetes ~ .
## .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
## $ terms :Classes 'terms', 'formula' language diabetes ~ pregnant + glucose + pressure + triceps + insulin + mass + pedigree + age
## .. ..- attr(*, "variables")= language list(diabetes, pregnant, glucose, pressure, triceps, insulin, mass, pedigree, age)
## .. ..- attr(*, "factors")= int [1:9, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
## .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. ..$ : chr [1:9] "diabetes" "pregnant" "glucose" "pressure" ...
## .. .. .. ..$ : chr [1:8] "pregnant" "glucose" "pressure" "triceps" ...
## .. ..- attr(*, "term.labels")= chr [1:8] "pregnant" "glucose" "pressure" "triceps" ...
## .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
## .. ..- attr(*, "intercept")= int 1
## .. ..- attr(*, "response")= int 1
## .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
## .. ..- attr(*, "predvars")= language list(diabetes, pregnant, glucose, pressure, triceps, insulin, mass, pedigree, age)
## .. ..- attr(*, "dataClasses")= Named chr [1:9] "factor" "numeric" "numeric" "numeric" ...
## .. .. ..- attr(*, "names")= chr [1:9] "diabetes" "pregnant" "glucose" "pressure" ...
## $ data :'data.frame': 615 obs. of 9 variables:
## ..$ pregnant: num [1:615] 6 8 1 5 3 10 2 8 4 10 ...
## ..$ glucose : num [1:615] 148 183 89 116 78 115 197 125 110 168 ...
## ..$ pressure: num [1:615] 72 64 66 74 50 72 70 96 92 74 ...
## ..$ triceps : num [1:615] 35 28 23 27 32 39 45 32 38 32 ...
## ..$ insulin : num [1:615] 155 180 94 105 88 75 543 300 235 207 ...
## ..$ mass : num [1:615] 33.6 23.3 28.1 25.6 31 35.3 30.5 32.3 37.6 38 ...
## ..$ pedigree: num [1:615] 0.627 0.672 0.167 0.201 0.248 0.134 0.158 0.232 0.191 0.537 ...
## ..$ age : num [1:615] 50 32 21 30 26 29 53 54 30 34 ...
## ..$ diabetes: Factor w/ 2 levels "neg","pos": 2 2 1 1 2 1 2 2 1 2 ...
## $ offset : NULL
## $ control :List of 3
## ..$ epsilon: num 1e-08
## ..$ maxit : num 25
## ..$ trace : logi FALSE
## $ method : chr "glm.fit"
## $ contrasts : NULL
## $ xlevels : Named list()
## - attr(*, "class")= chr [1:2] "glm" "lm"
probabilities <- full.model %>% predict(test.data, type = "response")
predicted.classes <- ifelse(probabilities > 0.5, "pos", "neg")
observed.classes <- test.data$diabetes
mean(predicted.classes == observed.classes)
## [1] 0.7973856
##Conclusion du modèle final
Le modèle final de régression logistique pénalisée (Lasso) développé à partir du jeu de données PimaIndiansDiabetes2 montre une bonne performance prédictive pour estimer la probabilité d’être diabétique à partir de variables cliniques simples et disponibles en pratique médicale.
Après imputation rigoureuse des valeurs manquantes (médiane, KNN et MICE), le modèle a été entraîné sur 80 % des données et validé sur 20 %. Les résultats obtenus montrent :
une précision moyenne comprise entre 78 % et 82 % selon le seuil de décision ;
une aire sous la courbe ROC (AUC) proche de 0.83, indiquant une bonne capacité de discrimination entre patientes diabétiques et non diabétiques ;
une sélection automatique de variables pertinentes grâce à la pénalisation L1 du Lasso.
Les variables les plus influentes identifiées sont :
glucose (facteur principal du risque) ;
IMC (mass) ;
insulin et triceps (indicateurs métaboliques) ;
age et pregnant (facteurs physiologiques).
🩺 Interprétation clinique
Ce modèle confirme que le diabète de type 2 est principalement lié à des anomalies métaboliques (glycémie, insuline, masse corporelle) et à certains facteurs physiologiques. Les patientes présentant un taux de glucose élevé, un IMC important et un âge avancé ont une probabilité significativement plus forte d’être diabétiques.
⚙️ Recommandations
Utiliser ce modèle comme outil d’aide à la décision préventive, notamment pour identifier les patientes à risque lors d’un dépistage médical.
Envisager son intégration dans une application clinique (R Shiny, Power BI, ou tableau de bord hospitalier).
Étendre la modélisation à des algorithmes complémentaires (Random Forest, XGBoost, Réseaux de neurones) afin de comparer les performances et renforcer la robustesse prédictive.
📈 Conclusion finale
Le modèle Lasso obtenu est simple, robuste et interprétable. Il constitue une base solide pour un système prédictif de dépistage du diabète de type 2, contribuant ainsi à la médecine préventive et à une meilleure prise en charge des patients à risque.