Skip to content

Commit 4dc9e0b

Browse files
First version of C03La_roc
1 parent 4f29aee commit 4dc9e0b

File tree

2 files changed

+363
-5
lines changed

2 files changed

+363
-5
lines changed

inst/tutorials/C02Lb_ml2/C02Lb_ml2.Rmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ predict(pumpkins_knn, pumpkins_test) |> confusion(___$class) |> summary()
196196
predict(___, ___) |> confusion(___$___) |> summary()
197197
# forêt aléatoire
198198
predict(___, ____) |> confusion(___$___) |> summary()
199+
200+
## Attention, le prochain indice est la solution ##
199201
```
200202

201203
```{r predict_h2-solution}

inst/tutorials/C03La_roc/C03La_roc.Rmd

Lines changed: 361 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: "Guyliann Engels & Philippe Grosjean"
44
description: "**SDD III Module 3** Effet des proportions sur les métriques et courbes ROC."
55
tutorial:
66
id: "C03La_roc"
7-
version: 2.0.0/0
7+
version: 2.0.0/9
88
output:
99
learnr::tutorial:
1010
progressive: true
@@ -17,7 +17,53 @@ BioDataScience3::learnr_setup()
1717
SciViews::R()
1818
library(mlearning)
1919
20-
# ...
20+
# Importation des données
21+
breast <- read("BreastCancer", package = "mlbench")
22+
breast <- janitor::clean_names(breast)
23+
breast <- na_omit(breast, "bare_nuclei")
24+
breast <- sselect(breast, -id)
25+
26+
# Partitionnement récursif -------
27+
## rpart1
28+
set.seed(12)
29+
breast_part <- mlRpart(data = breast, class~.)
30+
breast_pred1 <- cvpredict(breast_part, cv.k = 5)
31+
part1_conf <- confusion(breast_pred1, breast$class)
32+
part1_tab <- summary(part1_conf)
33+
34+
## rpart2
35+
# sous ensemble des personnes malades
36+
breast %>.%
37+
filter(., class == "malignant") %>.%
38+
sample_n(., 200) %->% br_m2
39+
# sous ensemble des personnes saines
40+
breast %>.%
41+
filter(., class == "benign") %>.%
42+
sample_n(., 50) %->% br_b2
43+
# Combinaison des tableaux
44+
breast2 %<-% bind_rows(br_m2, br_b2)
45+
# Creation du model
46+
breast_part2 <- mlRpart(data = breast2, class~.)
47+
# Evaluation du model
48+
breast_pred2 <- cvpredict(breast_part2, cv.k = 5)
49+
part2_conf <- confusion(breast_pred2, breast2$class)
50+
part2_tab <- summary(part2_conf)
51+
52+
# Proba a priori
53+
breast_prior <- table(breast$class) / nrow(breast)
54+
breast_prior <- structure(as.numeric(breast_prior), names = names(breast_prior))
55+
part2_conf2 <- part2_conf
56+
prior(part2_conf2) <- breast_prior
57+
part2_conf2_tab <- summary(part2_conf2)
58+
59+
#part1_tab
60+
#part2_tab
61+
#part2_conf2_tab
62+
63+
# ROC -----
64+
set.seed(12)
65+
breast_pred <- cvpredict(breast_part, cv.k = 5, type = "membership")
66+
#head(breast_pred)
2167
```
2268

2369
```{r, echo=FALSE}
@@ -32,12 +78,322 @@ BioDataScience3::learnr_server(input, output, session)
3278

3379
## Objectifs
3480

35-
- ...
81+
Ce tutoriel doit encore être écrit. Vous devez probablement penser à installer une version plus récente du package qui contient les exercices finalisés !
82+
83+
Un classifieur qui ne commet pas d'erreur. Ce n'est pas réaliste (ou très très peu probable). Les métriques sont calculées sur base d'une matrice de confusion qui dénombre les vrais positifs, les faux positifs, les vrais négatifs et les faux négatifs. Ces métriques permettent d'évaluer la qualité d'un classifieur. Le nombre d'items dans chaque groupe de la variable à prédire va donc influencer ces métriques. Ce tutoriel s'intéresse tout d'abord à l'effet de proportions.
84+
85+
Un autre manière d'influencer notre classifueur va être de modifieur le seuil de détection. Etudier la variation du seuil de détection est l'objectif de la courbe ROC . Cette courbe représente le comportement de notre classifieur à deux classes pour tous les seuils de détection possibles.
3686

3787
## Effet des proportions sur les métriques
3888

39-
TODO: ce tutoriel doit encore être écrit. Vous devez probablement penser à installer une version plus récente du package qui contient les exercices finalisés !
89+
Lorsqu'un classifieur ne commet aucune erreur. Les proportions de chacune des classes n'ont aucune importance. Qu'il y ait 10, 1000, 10000 individus par classe n'aura aucun effet sur la qualité du classifieur que l'on détermine à l'aide des métriques. Par contre, dès qu'il y a des erreurs de classification, les proportions de chaque classe dans le set d'apprentissage vont avoir un effet dans les résultats de chaque métrique. Il peut être intéressant de modifier les proportions relatives de chaque classe afin de maximiser certaines métriques comme la précision ou le rappel. Cela va avoir généralement pour effet de réduire le taux de précision global.
90+
91+
Comme nous l'avons précisez depuis le premier module du cours de SDD III, il faut définir les métriques d'intérêt en fonction de la problématique que l'on étudie. Souhaite-t-on un classifieur qui commet globalement peu d'erreurs ou bien un classifieur très précis pour une classe particulière ? C'est à vous en tant qu'expert de le définir.
92+
93+
Vous avez à votre disposition le tableau `BreastCancer` du package {mlbench}. N'hésitez pas à consulter la page d'aide de ce tableau afin d'en apprendre davantage.
94+
95+
```{r, echo = TRUE}
96+
breast <- read("BreastCancer", package = "mlbench")
97+
breast <- janitor::clean_names(breast)
98+
```
99+
100+
Ce tableau comprend `r nrow(breast)` individus et `r ncol(breast)`.
101+
102+
```{r, echo = TRUE}
103+
skimr::skim(breast)
104+
```
105+
106+
Quelques lignes du tableau de données sont éliminées afin de se débarrasser des valeurs manquantes dans le tableau. La variable `id` est également éliminée. Elle n'est pas utile dans notre analyse.
107+
108+
```{r, echo=TRUE}
109+
# élimination des valeurs manquantes.
110+
breast <- na_omit(breast, "bare_nuclei")
111+
# Suppression de la colonne id
112+
breast <- sselect(breast, -id)
113+
```
114+
115+
La répartition entre les patients atteints d'une tumeur bénigne et maligne n'est pas homogène dans ce tableau.
116+
117+
```{r}
118+
table(breast$class)
119+
```
120+
121+
Les médecins font appel à vous afin de mettre en place un classifieur capable de trouver un maximum de personne atteint d'une tumeur maligne.
122+
123+
Ils acceptent que le classifieur se trompe et prédisent des faux positifs. Par contre, ils ne souhaitent pas rater de patients malades.
124+
125+
Réalisez un premier classifieur utilisant le partitionnement récursif et la validation croisée 5 fois afin d'employer un maximum d'observations. Nommez ce classifieur `breast_part`.
126+
127+
```{r rpart1_h2, exercise = TRUE}
128+
set.seed(12)
129+
# Création du classifieur
130+
breast_part <- ml___(data = ___, ___~___)
131+
# Evaluation du classifieur
132+
cvpredict(___, cv.k = ___)|> confusion(___$___) |> summary()
133+
```
134+
135+
```{r rpart1_h2-hint-1}
136+
set.seed(12)
137+
# Création du classifieur
138+
breast_part <- mlRpart(data = breast, class~.)
139+
# Evaluation du classifieur
140+
cvpredict(___, cv.k = ___)|> confusion(___$___) |> summary()
141+
142+
## Attention, le prochain indice est la solution ##
143+
```
144+
145+
```{r rpart1_h2-solution}
146+
set.seed(12)
147+
# Création du classifieur
148+
breast_part <- mlRpart(data = breast, class~.)
149+
# Evaluation du classifieur
150+
cvpredict(breast_part, cv.k = 5)|> confusion(breast$class) |> summary()
151+
```
152+
153+
```{r rpart1_h2-check}
154+
grade_code("Bien joué ! Vous avez réalisé et évalué votre classifieur.")
155+
```
156+
157+
```{r qu_rpart}
158+
question("Quel est la valeur de taux de vrais positifs pour les personnes malades ?",
159+
answer(sprintf("%.4f", part1_tab["malignant",]$Recall), correct = TRUE),
160+
answer(sprintf("%.4f", part1_tab["malignant",]$Specificity)),
161+
answer(sprintf("%.4f", part1_tab["malignant",]$LRPT)),
162+
answer(sprintf("%.4f", part1_tab["malignant",]$FDR)),
163+
allow_retry = TRUE,
164+
submit_button = "Soumettre une réponse",
165+
try_again_button = "Resoumettre une réponse",
166+
incorrect = "Mauvaise réponse. Recommencez et analysez plus finement les métriques associés à ce classifieur.",
167+
correct = "Bravo, c'est correct !")
168+
```
169+
170+
À présent, proposez un nouveau classifieur utilisant à nouveau le partitionnement récursif avec une validation croisée 5 fois. Modifiez le set d'apprentissage afin d'avoir 200 patients malades et 100 patients sains.
171+
172+
```{r split_h2, exercise = TRUE}
173+
set.seed(12)
174+
# sous ensemble des personnes malades
175+
breast %>.%
176+
filter(., ___ == ___) %>.%
177+
sample_n(., ___) %->% br_m2
178+
# sous ensemble des personnes saines
179+
breast %>.%
180+
filter(., ___ == ___) %>.%
181+
sample_n(., ___) %->% br_b2
182+
# Combinaison des tableaux
183+
breast2 %<-% bind_rows(___, ___)
184+
table(breast2$class)
185+
```
186+
187+
```{r split_h2-hint-1}
188+
set.seed(12)
189+
# sous ensemble des personnes malades
190+
breast %>.%
191+
filter(., class == ___) %>.%
192+
sample_n(., ___) %->% br_m2
193+
# sous ensemble des personnes saines
194+
breast %>.%
195+
filter(., class == ___) %>.%
196+
sample_n(., ___) %->% br_b2
197+
# Combinaison des tableaux
198+
breast2 %<-% bind_rows(br_m2, br_b2)
199+
table(breast2$class)
200+
201+
## Attention, le prochain indice est la solution ##
202+
```
203+
204+
```{r split_h2-solution}
205+
set.seed(12)
206+
# sous ensemble des personnes malades
207+
breast %>.%
208+
filter(., class == "malignant") %>.%
209+
sample_n(., 200) %->% br_m2
210+
# sous ensemble des personnes saines
211+
breast %>.%
212+
filter(., class == "benign") %>.%
213+
sample_n(., 100) %->% br_b2
214+
# Combinaison des tableaux
215+
breast2 %<-% bind_rows(br_m2, br_b2)
216+
table(breast2$class)
217+
```
218+
219+
```{r split_h2-check}
220+
grade_code("Bien joué ! Vous avez divisé en deux sous ensembles puis vous avez recombiné ces sous ensembles.")
221+
```
222+
223+
Calculez le second classifieur.
224+
225+
```{r rpart2_h2, exercise = TRUE}
226+
set.seed(12)
227+
breast_part2 <- ml___(data = ___, ___~___)
228+
cvpredict(breast_part2, cv.k = ___) |> confusion(___$___) ->
229+
part2_conf
230+
summary(part2_conf)
231+
```
232+
233+
```{r rpart2_h2-hint-1}
234+
set.seed(12)
235+
breast_part2 <- mlRpart(data = breast2, class~.)
236+
cvpredict(breast_part2, cv.k = ___) |> confusion(___$___) ->
237+
part2_conf
238+
summary(part2_conf)
239+
240+
## Attention, le prochain indice est la solution ##
241+
```
242+
243+
```{r rpart2_h2-solution}
244+
set.seed(12)
245+
breast_part2 <- mlRpart(data = breast2, class~.)
246+
cvpredict(breast_part2, cv.k = 5) |> confusion(breast2$class) ->
247+
part2_conf
248+
summary(part2_conf)
249+
```
250+
251+
```{r rpart2_h2-check}
252+
grade_code("Bravo ! Vous venez de réalsier et d'évaluer le second classifieur.")
253+
```
254+
255+
Définissez les probabilités *a priori* et corrigez la matrice de confusion. Vous avez calculé la matrice de confusion précédemment et l'avez nommée `part2_conf`.
256+
257+
```{r prior_h2, exercise = TRUE}
258+
# Calcul des probabilités a priori
259+
breast_prior <- table(___$___) / nrow(___)
260+
breast_prior <- structure(as.numeric(breast_prior), names = names(breast_prior))
261+
breast_prior
262+
# Adaptation de la matrice de confusion
263+
prior(___) <- breast_prior
264+
summary(___)
265+
```
266+
267+
```{r prior_h2-hint-1}
268+
# Calcul des probabilités a priori
269+
breast_prior <- table(breast$class) / nrow(___)
270+
breast_prior <- structure(as.numeric(breast_prior), names = names(breast_prior))
271+
breast_prior
272+
# Adaptation de la matrice de confusion
273+
prior(___) <- breast_prior
274+
summary(___)
275+
276+
## Attention, le prochain indice est la solution ##
277+
```
278+
279+
```{r prior_h2-solution}
280+
# Calcul des probabilités a priori
281+
breast_prior <- table(breast$class) / nrow(breast)
282+
breast_prior <- structure(as.numeric(breast_prior), names = names(breast_prior))
283+
breast_prior
284+
# Adaptation de la matrice de confusion
285+
prior(part2_conf) <- breast_prior
286+
summary(part2_conf)
287+
```
288+
289+
```{r prior_h2-check}
290+
grade_code("Bien joué ! Vous avez su adapter vos métriques en tenant compte des probabilités a priori. Répondez à la question suivante. ")
291+
```
292+
293+
```{r qu_rpart2}
294+
quiz(
295+
question("Quelle est la précision du second classifieur afin de détecter les personnes malades ?",
296+
answer(sprintf("%.4f", part2_conf2_tab["malignant",]$Precision), correct = TRUE),
297+
answer(sprintf("%.4f", part2_tab["malignant",]$Precision)),
298+
answer(sprintf("%.4f", part1_tab["malignant",]$Precision)),
299+
answer(sprintf("%.4f", part2_conf2_tab["benign",]$Precision)),
300+
allow_retry = TRUE,
301+
submit_button = "Soumettre une réponse",
302+
try_again_button = "Resoumettre une réponse",
303+
incorrect = "Mauvaise réponse. Recommencez et analysez plus finement les métriques associés aux classifieurs.",
304+
correct = "Bravo, c'est correct !"),
305+
question("Quel est la valeur de taux de vrais positifs pour les personnes malades ?",
306+
answer(sprintf("%.4f", part2_conf2_tab["malignant",]$Recall), correct = TRUE),
307+
answer(sprintf("%.4f", part2_tab["malignant",]$Specificity)),
308+
answer(sprintf("%.4f", part1_tab["malignant",]$Fscore)),
309+
answer(sprintf("%.4f", part2_conf2_tab["malignant",]$FDR)),
310+
allow_retry = TRUE,
311+
submit_button = "Soumettre une réponse",
312+
try_again_button = "Resoumettre une réponse",
313+
incorrect = "Mauvaise réponse. Recommencez et analysez plus finement les métriques associés aux classifieurs.",
314+
correct = "Bravo, c'est correct ! Vous pouvez observer que la modification des proportions a permis d'augmenter grandement le taux de vrais positifs. Cependant, nous observons une perte de précision. Les médecins vont préférer détecter un maximum de personnes malades avec quelques faux positifs.")
315+
)
316+
```
40317

41318
## courbes ROC
42319

43-
...
320+
Dans la section précédente, nous avons employé les proportions relatives afin de modifier les performances de notre classifieur (rappel VS précision). Il est possible de modifier le seuil de détection. La courbe ROC permet d'étudier tous les seuils de détection pour un classifieur à deux classes.
321+
322+
Outre la variation des proportions relatives des individus dans le set d'apprentissage, nous pouvons aussi faire varier les performances de notre classifieur entre rappel et précision en modifiant le seuil de détection.
323+
324+
```{r, echo=TRUE}
325+
set.seed(12)
326+
breast_pred <- cvpredict(breast_part, cv.k = 5, type = "membership")
327+
head(breast_pred)
328+
```
329+
330+
Réalisez en R de base le graphique de la courbe ROC. Vous devez commencer par formater les prédictions pour ROCR et nommer cet objet `pred_obj`. Ensuite, vous devez calculer les performances de votre `pred_obj` et le nommer `perf`. Déterminer les taux de vrais positifs (`tpr`) et le taux de faux positifs (`fpr`).
331+
332+
```{r roc_h2, exercise = TRUE}
333+
library(ROCR)
334+
# 1) Formater les prédictions pour ROCR
335+
___ <- prediction(breast_pred[,"malignant"], breast$class == "malignant")
336+
# 2) Calculer les performances avec les 2 métriques tpr et fpr
337+
___<- performance(___, ___, ___)
338+
# 3) Tracer le graphique ROC
339+
plot(___)
340+
abline(a = 0, b = 1, lty = 2)
341+
```
342+
343+
```{r roc_h2-hint-1}
344+
library(ROCR)
345+
# 1) Formater les prédictions pour ROCR
346+
___ <- prediction(breast_pred[,"malignant"], breast$class == "malignant")
347+
# 2) Calculer les performances avec les 2 métriques tpr et fpr
348+
___<- performance(___, "tpr", "fpr")
349+
# 3) Tracer le graphique ROC
350+
plot(___)
351+
abline(a = 0, b = 1, lty = 2)
352+
```
353+
354+
```{r roc_h2-solution}
355+
library(ROCR)
356+
# 1) Formater les prédictions pour ROCR
357+
pred_obj <- prediction(breast_pred[,"malignant"], breast$class == "malignant")
358+
# 2) Calculer les performances avec les 2 métriques tpr et fpr
359+
perf <- performance(pred_obj, "tpr", "fpr")
360+
# 3) Tracer le graphique ROC
361+
plot(perf)
362+
abline(a = 0, b = 1, lty = 2)
363+
```
364+
365+
```{r roc_h2-check}
366+
grade_code("Bravo ! Vous avez obtenu le graphique souhaité. On observe que le taux de vrais positifs augmente très rapidement.")
367+
```
368+
369+
Déterminez l'aire sous la courbe à l'aide de la fonction `auc()` du package {pROC}. Employez l'objet `breast_pred` explicité ci-dessus.
370+
371+
```{r auc_h2, exercise = TRUE}
372+
___::___(___$___, ___[, "malignant"])
373+
```
374+
375+
```{r auc_h2-hint-1}
376+
___::auc(___$___, ___[, "malignant"])
377+
```
378+
379+
```{r auc_h2-solution}
380+
pROC::auc(breast$class, breast_pred[, "malignant"])
381+
```
382+
383+
```{r auc_h2-check}
384+
grade_code("Bien joué ! Vous avez déterminé la valeur de l'aire sous la courbe ROC.")
385+
```
386+
387+
## Conclusion
388+
389+
Bien joué ! Vous venez de découvrir l'effet des proportions sur le set d'apprentissage et la courbe ROC. Votre boite à outils s'étoffe de module en module. En plus de choisir un modèle pour votre classifieur, vous apprenez à l'optimiser.
390+
391+
```{r comm_noscore, echo=FALSE}
392+
question_text(
393+
"Laissez-nous vos impressions sur cet outil pédagogique",
394+
answer("", TRUE, message = "Pas de commentaires... C'est bien aussi."),
395+
incorrect = "Vos commentaires sont enregistrés.",
396+
placeholder = "Entrez vos commentaires ici...",
397+
allow_retry = TRUE
398+
)
399+
```

0 commit comments

Comments
 (0)