Skip to content
Snippets Groups Projects
Commit e7ce2f57 authored by Elise Maigné's avatar Elise Maigné
Browse files

update pres

parent 3549a59f
No related branches found
No related tags found
No related merge requests found
.fontsize80pct {
font-size: 80%;
}
images/evol_biais_variance.png

49.8 KiB

index.qmd 0 → 100644
---
title: "Eviter le sur-apprentissage en machine learning"
subtitle: "Groupe Biopuces"
author:
- name: "**Elise Maigné**"
email: elise.maigne@inrae.fr
date: today
date-format: long
execute:
echo: false
bibliography: mybib.bib
css: custom_css.css
format:
inrae-revealjs :
fontsize: 1.9em
footer: "Présentation Biopuces"
mermaid:
theme: forest
include-in-header:
- text: |
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js""></script>
<script type="text/javascript">
$(document).ready(function() {
$('body').prepend('<div class=\"zoomDiv\"><img src=\"\" class=\"zoomImg\"></div>');
// onClick function for all plots (img's)
$('img:not(.zoomImg)').click(function() {
$('.zoomImg').attr('src', $(this).attr('src')).css({width: '100%'});
$('.zoomDiv').css({opacity: '1', width: 'auto', border: '1px solid white', borderRadius: '5px', position: 'fixed', top: '50%', left: '50%', marginRight: '-50%', transform: 'translate(-50%, -50%)', boxShadow: '0px 0px 50px #888888', zIndex: '50', overflow: 'auto', maxHeight: '100%', backgroundColor: 'white'});
});
// onClick function for zoomImg
$('img.zoomImg').click(function() {
$('.zoomDiv').css({opacity: '0', width: '0%'});
});
});
</script>
---
```{r}
library(ggplot2)
library(patchwork)
library(hrbrthemes)
library(ggpubr)
```
## Modèle descriptif VS modèle prédictif
**Analyse descriptive**
Faire un modèle pour expliquer (**décrire**) ce qu'il y a dans les données (la force d'une relation, l'intensité de phénomènes observés sur les données, ...).
. . .
**Analyse prédictive**
Construire un modèle pour catégoriser (**prédire**) sur un individu (sample) une caractéristique.
- **Prédiction supervisée** : les données sont pré-catégorisée (la caractéristique est connue, au moins sur une partie des données)
- **Prédiction non supervisée** : la caractéristique est inconnue au départ
## Qu'est-ce que le surapprentissage ?
```{r}
set.seed(12345) # Create example data frame
x <- seq(1,40, length=50) - 20
y <- rnorm(50, mean=0, sd=500) + 1.1 * x^3
df <- data.frame(x, y)
p1 <- ggplot(df, aes(x=x, y=y)) +
geom_point() +
hrbrthemes::theme_ipsum() +
theme(plot.margin = unit(c(0, 0.5, 0, 0.5), "cm"),
axis.text.x = element_blank(),
axis.text.y = element_blank())
my_mod3 <- lm(y~ x + I(x^2) + I(x^3), data=df)
fitok <- data.frame("x" = sort(df$x),
"ypred" = fitted(my_mod3)[order(df$x)])
#| echo: false
p2 <- p1 + geom_line(data=fitok, aes(x=x, y=ypred), col="#88CC88", linewidth=2, alpha=0.7) +
labs(title="Modélisation correcte")
my_mod1 <- lm(y~x, data=df)
underfit <- data.frame("x" = sort(df$x),
"ypred" = fitted(my_mod1)[order(df$x)])
p3 <- p1 +
geom_line(data=underfit, aes(x=x, y=ypred), col="#cc0066", size=2, alpha=0.7) +
labs(title="Sous apprentissage")
xnam <- paste0("I(x^", 1:25, ")")
fmla <- as.formula(paste("y ~ ", paste(xnam, collapse= "+")))
my_mod25 <- lm(fmla, data=df)
overfit <- data.frame("x" = sort(df$x),
"ypred" = fitted(my_mod25)[order(df$x)])
p4 <- p1 +
geom_line(data=overfit, aes(x=x, y=ypred), col="#cc0066", size=2, alpha=0.7) +
labs(title="Sur apprentissage")
p3 + p2 + p4
```
**Objectif** : séparer ce qui est de la tendance et ce qui est du bruit.
## Qu'est-ce que le surapprentissage ?
:::: {.columns}
::: {.column width=50%}
```{r}
p3 + p2 + p4
```
:::
::: {.column width=50%}
**Sous-apprentissage** = plus de biais, moins de variance
**Sur-apprentissage** = plus de variance, moins de biais
:::
::::
## Le processus du machine learning
::: columns
::: {.column width="40%"}
```{mermaid}
%%| fig-width: 10
flowchart TD
A[Données] --> B[Modèle optimal]
B --> B
B --> C[Validation sur<br>nouvelles données]
```
:::
::: {.column width="60%"}
::: fragment
### Phase d'entrainement
On ajuste un modèle jusqu'à avoir de bons résultats (ajustement des paramètres, choix des variables, ...).
Processus itératif.
:::
::: fragment
### Phase de test
On teste/valide ce modèle..
:::
:::
:::
## Processus général de machine learning
```{r}
dataexample <- data.frame(ind=1:100, step1 = "Dataset",
step2 = c(rep("Train", 80), rep("Test", 20)),
step3 = c(rep("Train", 64), rep("Validation",16), rep("Test", 20)),
y=c(rep("1", 5), rep("0", 15)))
dataexample$step2 <- factor(dataexample$step2, levels=c("Train", "Test"))
dataexample$step3 <- factor(dataexample$step3, levels=c("Train", "Validation", "Test"))
vectColors <- c("Train"="#8DA0CB", "Test"= "#66C2A5" , "Validation"= "#FC8D62", "Dataset"= "#E5C494")
mytheme <- hrbrthemes::theme_ipsum() +
theme(plot.margin = margin(c(0, 0.5, 0, 0.5), "cm"),
legend.position = "none",
axis.text.x = element_blank(),
axis.ticks = element_blank(),
axis.title.x = element_blank(),
panel.grid = element_blank(),
plot.title = element_text(size=14))
```
```{r}
#| fig-width: 4
pphases <-
ggplot(dataexample, aes(x=step1, fill=step2)) +
geom_bar(linewidth=0, width = 1.5) +
mytheme +
theme(axis.text.y = element_blank(),
axis.title.y = element_blank(),
axis.ticks.y = element_blank()) +
scale_fill_manual(values=c("#855C75", "#D9AF6B")) +
annotate("text", x=1, y=c(10, 60), label=c("Phase\nde\ntest", "Phase\nd'entrainement"), angle = 90)
```
::: columns
::: {.column width="40%"}
```{r}
#| fig-width: 2.2
pstep1 <- ggplot(dataexample, aes(x=step1, fill=step1, group=ind)) +
geom_bar(linewidth=0.1, width = 1.5, color="black") +
mytheme +
scale_fill_manual(values=vectColors) +
labs(y="Individuals", title="Dataset")
pstep1 + pphases + patchwork::plot_layout(widths = c(2, 2))
```
:::
::: {.column width="60%"}
Exemple d'un jeu de données avec 100 observations.
:::
:::
## Processus général de machine learning
::: columns
::: {.column width="40%"}
```{r}
#| fig-width: 4
pstep2 <-
ggplot(dataexample, aes(x=step1, fill=step2)) +
geom_bar(linewidth=0, width = 1.5) +
mytheme +
theme(axis.text.y = element_blank(),
axis.title.y = element_blank(),
axis.ticks.y = element_blank(),
plot.margin = margin(c(0, 0, 0, 20))) +
scale_fill_manual(values=vectColors) +
labs(y="Individuals",
title="Train/Test") +
annotate("text", x=1, y=c(10, 60), label=c("Test", "Train"))
pstep1 + pphases + pstep2 + patchwork::plot_layout(widths = c(5, 5, 10))
```
:::
::: {.column width="60%"}
On divise le jeu de données en deux échantillons : **train** et **test** (classiquement 60%/40%, 70%/30% ou 80%/20% ).
- **train** est l'échantillon sur lequel on va ajuster le modèle.
- **test** est l'échantillon sur lequel on va vérifier que le modèle s'applique bien à un autre jeu de données.
:::
:::
. . .
L'échantillon test ne doit JAMAIS être utilisé pendant la phase d'entraînement
. . .
N'empêche pas le sur-apprentissage !
## Processus général de machine learning
::: columns
::: {.column width="60%"}
```{r}
#| fig-width: 6
pstep3 <-
ggplot(dataexample, aes(x=step1, fill=step3)) +
geom_bar(linewidth=0, width = 1.5) +
mytheme +
theme(axis.text.y = element_blank(),
axis.title.y = element_blank(),
axis.ticks.y = element_blank(),
plot.margin = margin(c(0, 0, 0, 20))) +
scale_fill_manual(values=vectColors) +
labs(y="Individuals",
title="Train/Validation/\nTest") +
annotate("text", x=1, y=c(10, 28, 68), label=c("Test", "Validation", "Train"))
pstep1 + pphases + pstep2 + pstep3 + patchwork::plot_layout(widths = c(5, 5, 10, 10))
```
:::
::: {.column width="40%"}
L'échantillon de **validation** va nous servir à valider le modèle, pendant la phase d'entraînement.
::: {.fragment}
N'empêche toujours pas le sur-apprentissage !
:::
:::
:::
## Processus général de machine learning
![Processus générique machine learning [Source @boehmke2019hands]](https://bradleyboehmke.github.io/HOML/images/modeling_process.png)
## Validation croisée
- **Holdout** (Train/Test/Validation seulement pour grands jeux de données, et sous certaines conditions)
. . .
Exemples de techniques de validation croisée :
- **Repeated random sub-sampling**
- **k-fold**
- **LOOCV** (leave-one-out cross-validation)
- **Bootstrapping**
- ...
Voir par exemple :
```{r}
#| echo: true
?caret::trainControl # Voir argument method
```
## Validation croisée exemple k-fold
![Exemple k-fold. [Source @boehmke2019hands]](https://bradleyboehmke.github.io/HOML/images/cv.png)
# La théorie VS la vie {.inverse}
## La théorie VS la vie
L'approche Train/Test/Validation (i.e. Holdout) marche uniquement si on a des jeux de données très grands [voir @Molinaro2005; @hawkins2003] et ne permet pas complètement d'enlever le sur-apprentissage.
On trouve aussi :
- petits échantillons
- classes déséquilibrées
- plus de variables que d'individus
. . .
On va contrôler :
- le tirage aléatoire
- le processus de validation (validation croisée)
# Contrôle du tirage aléatoire {.inverse}
## Comment diviser les données ?
Pour la division train/test :
**Simple tirage aléatoire.**
On va tirer aléatoirement 30% (ou 20% ou 40%) des données totales pour former l'échantillon test. Le reste formera l'échantillon d'apprentissage.
. . .
**Tirage aléatoire stratifié.**
On veut que la distribution de la variable à expliquer (cible) soit la même dans les échantillons. Le tirage se fait soit par quantile (var. continue) soit par classe (var. catégorielle). Parfois utile par exemple dans des distributions déséquilibrées.
. . .
Dans tous les cas toujours fixer une graine pour pouvoir reproduire le tirage (par ex. en R : `set.seed()`\`).
# Déséquilibre des classes {.inverse}
## Déséquilibre des classes
Exemple dans un problème de classification on essaie de prédire Y qui est distribué 1: 5% et 0: 95%.
```{r}
#| fig-cap: "Cas de déséquilibre des classes : une classe est largement minoritaire."
set.seed(123)
dtplot <- rbind(data.frame(x=rnorm(190), y=rnorm(190), z="A"),
data.frame(x=rnorm(10, mean=1, sd=0.2), y=rnorm(10, mean=1, sd=0.2), z="B"))
ggplot(data=dtplot, aes(x=x, y=y, color=z, shape=z)) +
geom_point(alpha=0.8, size=2) +
hrbrthemes::theme_ipsum() +
labs(x=NULL, y=NULL, title=NULL) +
theme(plot.margin = margin(c(0, 0, 0, 0), "cm"),
legend.position = "none") +
scale_color_manual(values=c("A"= "#66C2A5" , "B"= "#FC8D62"))
```
## Déséquilibre des classes - Rééchantillonnage
```{r}
#| echo: false
dataexample <- data.frame(x=1:20,
y=c(rep("Class2", 5), rep("Class1", 15)))
dsample <- caret::downSample(dataexample, factor(dataexample$y), yname="y")
usample <- caret::upSample(dataexample, factor(dataexample$y), yname="y")
```
```{r}
dataexample$ds <- "Echantillon d'apprentissage"
dsample$ds <- "DownSampling"
usample$ds <- "UpSampling"
colorsVect <- scales::hue_pal()(20)
colorsVect <- sample(colorsVect, replace = FALSE, size=20)
```
::: r-stack
::: fragment
```{r}
#| fig-width: 4
#| fig-height: 3.5
#| fig-align: "left"
ggplot(dataexample, aes(x=y, fill=factor(x))) +
geom_bar() +
geom_text(aes(label=x, y=1), position = position_stack(vjust = 0.5)) +
scale_fill_manual(values=colorsVect) +
facet_wrap(vars(ds)) +
hrbrthemes::theme_ipsum() +
labs(x=NULL, y=NULL) +
theme(legend.position = "none",
axis.text.y = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.margin=margin(c(0, 0, 0, 0), "cm"))
```
:::
::: fragment
```{r}
#| fig-width: 12
#| fig-height: 4
#| fig-align: "left"
ggplot(rbind(dataexample, dsample, usample), aes(x=y, fill=factor(x))) +
geom_bar() +
geom_text(aes(label=x, y=1), position = position_stack(vjust = 0.5)) +
scale_fill_manual(values=colorsVect) +
facet_wrap(vars(ds)) +
hrbrthemes::theme_ipsum() +
labs(x=NULL, y=NULL) +
theme(legend.position = "none",
axis.text.y = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.margin=margin(c(0, 0, 0, 0), "cm"))
```
:::
:::
::: fragment
Selon les modèles on n'est pas obligé d''avoir 50/50. Ex. Arbres : 5/10% peuvent suffire.
:::
## Déséquilibre des classes - Rééchantillonnage
- UpSampling (ou OverSampling) : clonage aléatoire (plutôt pour méthodes linéaires)
::: fragment
Et aussi :
- **SMOTE** (Synthetic Minority Oversampling TEchnique - [@chawla2002smote]), **SMOTE-NC** si variables catégorielles,
::: {.fontsize80pct}
Des individus ressemblant à ceux de la classe minoritaire sont générés. 2 paramètres, $k$ et $\alpha$. moyenne pondérée d'un voisin parmi les k plus proches.
:::
- **ROSE** (Random Over Sampling Examples - [@menardi2014training]).
::: {.fontsize80pct}
Technique basée sur le bootstrap et des méthodes à noyaux. Génère des individus artificiels autour des individus. 2 paramètres à ajuster.
:::
```{r}
?caret::trainControl # Voir argument sampling
```
:::
## Déséquilibre des classes - Autres méthodes
Peut être pris en compte directement par l'algorithme (à ne pas combiner avec un rééchantillonnage).
- rééchantillonnage interne à la volée (bagging, boosting), sur-pondération de la classe minoritaire (poids), ...
Pris en compte sur l'erreur de classification :
- on ajuste le calcul à postériori
::: fragment
Dans tous les cas, une méthode mal utilisée peut accroître les biais du modèle.
:::
## Déséquilibre des classes - Mesures d'erreurs
# Hyperparamètres
## Hyperparamètres
**Paramètres** = estimés par le modèle $\neq$ **Hyperparamètres** fixés avant de faire tourner le modèle.
Exemple :
$$
y = \alpha + \beta x + \epsilon
$$
. . .
Puis on introduit une pénalité g(x) plus ou moins forte (\lambda \> 0) :
$$
y = \alpha + \beta x + \epsilon + \lambda g(x)
$$
## Hyperparamètres - Optimisation
Les différents paramètres sont à ajuster pendant le processus d'entrainement, le taux de rééchantillonnage peut l'être aussi.
. . .
**Techniques :**
- Essai de plusieurs valeurs. Lourde et attention à la reproductibilité mais relativement rapide.
- Recherche par grille (espacce fini)
- L'optimisation bayesienne (espace des paramètres)
Il existe des optimiseurs pour les hyperparamètres (voir par exemple `{tune}`).
## Hyperparamètres - Optimisation
![Source : https://leandeep.com/tradeoff-biais-variance/](images/evol_biais_variance.png)
Trouver un compromis entre biais et variance.
## TODO
Parler des biais.
Des types de mesures d'erreurs.
Des petits échantillons
@article{Molinaro2005,
author = {Molinaro, Annette M. and Simon, Richard and Pfeiffer, Ruth M.},
title = "{Prediction error estimation: a comparison of resampling methods}",
journal = {Bioinformatics},
volume = {21},
number = {15},
pages = {3301-3307},
year = {2005},
month = {05},
abstract = "{Motivation: In genomic studies, thousands of features are collected on relatively few samples. One of the goals of these studies is to build classifiers to predict the outcome of future observations. There are three inherent steps to this process: feature selection, model selection and prediction assessment. With a focus on prediction assessment, we compare several methods for estimating the true prediction error of a prediction model in the presence of feature selection.Results: For small studies where features are selected from thousands of candidates, the resubstitution and simple split-sample estimates are seriously biased. In these small samples, leave-one-out cross-validation (LOOCV), 10-fold cross-validation (CV) and the .632+ bootstrap have the smallest bias for diagonal discriminant analysis, nearest neighbor and classification trees. LOOCV and 10-fold CV have the smallest bias for linear discriminant analysis. Additionally, LOOCV, 5- and 10-fold CV, and the .632+ bootstrap have the lowest mean square error. The .632+ bootstrap is quite biased in small sample sizes with strong signal-to-noise ratios. Differences in performance among resampling methods are reduced as the number of specimens available increase.Contact: annette.molinaro@yale.eduSupplementary Information: A complete compilation of results and R code for simulations and analyses are available in Molinaro et al. (2005) (http://linus.nci.nih.gov/brb/TechReport.htm).}",
issn = {1367-4803},
doi = {10.1093/bioinformatics/bti499},
url = {https://doi.org/10.1093/bioinformatics/bti499},
eprint = {https://academic.oup.com/bioinformatics/article-pdf/21/15/3301/50340684/bioinformatics\_21\_15\_3301.pdf},
}
@article{hawkins2003,
author = {Hawkins, Douglas and Basak, Subhash and Mills, Denise},
year = {2003},
month = {03},
pages = {579-86},
title = {Assessing Model Fit by Cross-Validation},
volume = {43},
journal = {Journal of chemical information and computer sciences},
doi = {10.1021/ci025626i}
}
@book{boehmke2019hands,
title={Hands-on machine learning with R},
author={Boehmke, Brad and Greenwell, Brandon M},
year={2019},
publisher={CRC press}
}
@article{chawla2002smote,
title={SMOTE: synthetic minority over-sampling technique},
author={Chawla, Nitesh V and Bowyer, Kevin W and Hall, Lawrence O and Kegelmeyer, W Philip},
journal={Journal of artificial intelligence research},
volume={16},
pages={321--357},
year={2002}
}
@article{menardi2014training,
title={Training and assessing classification rules with imbalanced data},
author={Menardi, Giovanna and Torelli, Nicola},
journal={Data mining and knowledge discovery},
volume={28},
pages={92--122},
year={2014},
publisher={Springer}
}
---
title: "Prédiction et surapprentissage"
subtitle: "Groupe Biopuces"
author:
- name: "**Elise Maigné**"
email: elise.maigne@inrae.fr
date: today
date-format: long
format:
inrae-revealjs :
footer: "Présentation Biopuces"
---
```{r}
library(ggplot2)
library(patchwork)
library(hrbrthemes)
```
## Modèle descriptif VS modèle prédictif
**Analyse descriptive**
Faire un modèle pour expliquer (**décrire**) ce qu'il y a dans les données (la force d'une relation, l'intensité de phénomènes observés sur les données, ...)
. . .
**Analyse prédictive**
Construire un modèle pour catégoriser (**prédire**) sur un individu (sample) une caractéristique.
## Qu'est-ce que le surapprentissage ?
```{r}
#| echo: false
set.seed(12345) # Create example data frame
x <- seq(1,40, length=50) - 20
y <- rnorm(50, mean=0, sd=500) + 1.1 * x^3
df <- data.frame(x, y)
```
```{r}
#| echo: false
p1 <- ggplot(df, aes(x=x, y=y)) +
geom_point() +
hrbrthemes::theme_ipsum() +
theme(plot.margin = unit(c(1, 0.5, 1, 0.5), "cm"))
```
```{r}
#| echo: false
my_mod3 <- lm(y~ x + I(x^2) + I(x^3), data=df)
fitok <- data.frame("x" = sort(df$x),
"ypred" = fitted(my_mod3)[order(df$x)])
#| echo: false
p2 <- p1 + geom_line(data=fitok, aes(x=x, y=ypred), col="#88CC88", linewidth=2, alpha=0.7) +
labs(title="Modélisation correcte")
```
```{r}
#| echo: false
my_mod1 <- lm(y~x, data=df)
underfit <- data.frame("x" = sort(df$x),
"ypred" = fitted(my_mod1)[order(df$x)])
#| echo: false
p3 <- p1 +
geom_line(data=underfit, aes(x=x, y=ypred), col="#cc0066", size=2, alpha=0.7) +
labs(title="Sous apprentissage")
```
```{r}
#| echo: false
xnam <- paste0("I(x^", 1:25, ")")
fmla <- as.formula(paste("y ~ ", paste(xnam, collapse= "+")))
my_mod1 <- lm(fmla, data=df)
overfit <- data.frame("x" = sort(df$x),
"ypred" = fitted(my_mod1)[order(df$x)])
#| echo: false
p4 <- p1 +
geom_line(data=overfit, aes(x=x, y=ypred), col="#cc0066", size=2, alpha=0.7) +
labs(title="Sur apprentissage")
p3 + p2 + p4
```
Objectif = séparer ce qui est de la tendance et ce qui est du bruit.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment