Skip to content

Commit

Permalink
2ème relectures chapitres ML (#457)
Browse files Browse the repository at this point in the history
* mostly espaces insécables

* add reference funathon

* suggestions métriques

* ajout outliers et imputation

* espaces

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

* Update content/modelisation/0_preprocessing.qmd

---------

Co-authored-by: Lino Galiana <linogaliana@yahoo.fr>
  • Loading branch information
antoine-palazz and linogaliana committed Nov 23, 2023
1 parent 4960f2b commit a06a268
Show file tree
Hide file tree
Showing 25 changed files with 118 additions and 68 deletions.
2 changes: 1 addition & 1 deletion content/NLP/02_exoclean.qmd
Expand Up @@ -507,7 +507,7 @@ par la loi de Zipf, cf. exercice suivant).



### Aparté: la loi de Zipf
### Aparté : la loi de Zipf

::: {.cell .markdown}
```{=html}
Expand Down
2 changes: 1 addition & 1 deletion content/annexes/corrections.qmd
Expand Up @@ -50,7 +50,7 @@ print_badges("content/manipulation/02b_pandas_TP.qmd", correction=True)
```
:::

* [Exercices `Geopandas`](../manipulation/03_geopandas_TP.qmd):
* [Exercices `Geopandas`](../manipulation/03_geopandas_TP.qmd) :

::: {.cell .markdown}
```{python}
Expand Down
6 changes: 3 additions & 3 deletions content/getting-started/01_installation.qmd
Expand Up @@ -39,7 +39,7 @@ chapitre présente les badges suivants qui permettent d'ouvrir
la page *web* en question dans l'environnement de prédilection.
Par exemple, pour ouvrir le chapitre relatif à
`numpy` dans l'un des environnements temporaires proposés,
les badges suivants sont proposés:
les badges suivants sont proposés :

::: {.cell .markdown}
```{python}
Expand Down Expand Up @@ -216,8 +216,8 @@ jusqu'au
déploiement de visualisations automatiques[^1]) mais n'est pas très pratique pour
le griffonnage.

[^1] A cet égard, il est recommandé de consulter le cours de dernière année
de l'ENSAE déjà cité: https://ensae-reproductibilite.github.io/website/
[^1]: A cet égard, il est recommandé de consulter le cours de dernière année
de l'ENSAE déjà cité : https://ensae-reproductibilite.github.io/website/


[Kaggle](https://www.kaggle.com/notebooks) <i class="fab fa-kaggle"></i>
Expand Down
2 changes: 1 addition & 1 deletion content/getting-started/04_python_practice.qmd
Expand Up @@ -62,7 +62,7 @@ l'environnement est le `NAMESPACE`.
[sphinx](https://docs.readthedocs.io/en/stable/intro/getting-started-with-sphinx.html) et non de l'éditer
manuellement. (cf. [plus tard](#docfonctions)).
Les éléments qui s'en rapprochent dans un package `R` sont les vignettes.
* Les tests génériques des fonctions. Ce n'est pas obligatoire mais c'est recommandé: ça évite de découvrir deux jours
* Les tests génériques des fonctions. Ce n'est pas obligatoire mais c'est recommandé : ça évite de découvrir deux jours
avant un rendu de projet que la fonction ne produit pas le résultat espéré.
* Le `README.md` permet de créer une présentation du package qui s'affiche automatiquement sur
github/gitlab et le fichier `LICENSE` vise à protéger la propriété intellectuelle. Un certain nombre de licences
Expand Down
2 changes: 1 addition & 1 deletion content/getting-started/05_rappels_types.qmd
Expand Up @@ -400,7 +400,7 @@ nous allons
voir comment nous en servir.
Pour comprendre comment modifier un objet, il convient
de distinguer deux concepts, développés plus amplement
dans le chapitre dédié: les __attributs__ et les __méthodes__ :
dans le chapitre dédié : les __attributs__ et les __méthodes__ :

- Les _attributs_ décrivent la structure interne d'un objet. Par exemple,
la taille d'un objet, sa langue, etc.
Expand Down
2 changes: 1 addition & 1 deletion content/git/exogit.qmd
Expand Up @@ -271,7 +271,7 @@ sans s'en rendre compte.
En amont de l'exercice 2, pour les utilisateurs
du `SSPCloud`,
il est recommandé d'ouvrir un service `Jupyter`
en suivant les consignes suivantes:
en suivant les consignes suivantes :

* Dans la page `Mes services`, cliquer sur le bouton `Nouveau service` ;
* Choisir `Jupyter-Python` ;
Expand Down
2 changes: 1 addition & 1 deletion content/manipulation/01_numpy.qmd
Expand Up @@ -152,7 +152,7 @@ Il existe aussi des méthodes pratiques pour créer des array:
* séquences logiques : `np.arange` (suite) ou `np.linspace` (interpolation linéaire entre deux bornes)
* séquences ordonnées : _array_ rempli de zéros, de 1 ou d'un nombre désiré : `np.zeros`, `np.ones` ou `np.full`
* séquences aléatoires : fonctions de génération de nombres aléatoires : `np.rand.uniform`, `np.rand.normal`, etc.
* tableau sous forme de matrice identité: `np.eye`
* tableau sous forme de matrice identité : `np.eye`

Ceci donne ainsi, pour les séquences logiques:

Expand Down
4 changes: 2 additions & 2 deletions content/manipulation/02a_pandas_tutorial.qmd
Expand Up @@ -668,7 +668,7 @@ ou `df['Autres transports']`. C'est une manière préférable de procéder.

Pour accéder à une ou plusieurs valeurs d'un `DataFrame`,
il existe deux manières conseillées de procéder, selon la
forme des indices de lignes ou colonnes utilisés:
forme des indices de lignes ou colonnes utilisées :

* `df.loc` : utilise les labels
* `df.iloc` : utilise les indices
Expand Down Expand Up @@ -950,7 +950,7 @@ donnée en fin de cours.
Tant qu'on n'appelle pas une action sur un `DataFrame` par groupe, du type
`head` ou `display`, `pandas` n'effectue aucune opération. On parle de
*lazy evaluation*. Par exemple, le résultat de `df.groupby('dep')` est
une transformation qui n'est pas encore évaluée:
une transformation qui n'est pas encore évaluée :

```{python}
df.groupby('dep')
Expand Down
2 changes: 1 addition & 1 deletion content/manipulation/02b_pandas_TP.qmd
Expand Up @@ -370,7 +370,7 @@ utiliser le _package_ communautaire `pynsee` :
<h3 class="alert-heading"><i class="fa-solid fa-comment"></i> Note</h3>
```

Le _package_ `pynsee` comporte deux principaux points d'entrée:
Le _package_ `pynsee` comporte deux principaux points d'entrée :

- Les API de l'Insee, ce qui sera illustré dans le chapitre consacré.
- Quelques jeux de données directement issus du site web de
Expand Down
10 changes: 5 additions & 5 deletions content/manipulation/04a_webscraping_TP.qmd
Expand Up @@ -180,7 +180,7 @@ Citons, par exemple, les balises `<p>`, `<h1>`, `<h2>`, `<h3>`, `<strong>` ou `<
Le symbole ``< >`` est une balise : il sert à indiquer le début d'une partie. Le symbole `</ >` indique la fin de cette partie. La plupart des balises vont par paires, avec une *balise ouvrante* et une *balise fermante* (par exemple `<p>` et `</p>`).

Par exemple, les principales balises
définissant la structure d'un tableau sont les suivantes:
définissant la structure d'un tableau sont les suivantes :

| Balise | Description |
|-------------|------------------------------------|
Expand All @@ -196,7 +196,7 @@ définissant la structure d'un tableau sont les suivantes:

**Application : un tableau en HTML**

Le code `HTML` du tableau suivant:
Le code `HTML` du tableau suivant :

```{html}
<table>
Expand Down Expand Up @@ -485,7 +485,7 @@ print(rows[0])
```


La seconde ligne va correspondre à la ligne du premier club présent dans le tableau:
La seconde ligne va correspondre à la ligne du premier club présent dans le tableau :

```{python}
#| echo: true
Expand Down Expand Up @@ -555,7 +555,7 @@ data_participants.head()
```


5️⃣ Récupérer les en-têtes du tableau:
5️⃣ Récupérer les en-têtes du tableau :

```{python}
#| echo: true
Expand Down Expand Up @@ -1337,7 +1337,7 @@ search_button.click()

`Selenium` permet de capturer l'image qu'on verrait dans le navigateur
avec `get_screenshot_as_png`. Cela peut être utile pour vérifier qu'on
a fait la bonne action:
a fait la bonne action :

```{python}
#| output: false
Expand Down
6 changes: 3 additions & 3 deletions content/manipulation/04b_regex_TP.qmd
Expand Up @@ -117,7 +117,7 @@ print(re.search(pattern, "J'ai un chapeau rond."))
```

Cependant, dans le dernier cas, nous ne trouvons pas
le _pattern_ recherché:
le _pattern_ recherché :

```{python}
print(re.search(pattern, "La soupe est chaude."))
Expand All @@ -137,7 +137,7 @@ ou les ancres (`^`, `$`...)
Dans l'exemple précédent,
nous retrouvions deux quantifieurs accolés `.+`. Le premier (`.`) signifie n'importe quel caractère[^1]. Le deuxième (`+`) signifie _"répète le pattern précédent"_.
Dans notre cas, la combinaison `.+` permet ainsi de répéter n'importe quel caractère avant de trouver un _n_.
Le nombre de fois est indeterminé: cela peut ne pas être pas nécessaire d'intercaler des caractères avant le _n_
Le nombre de fois est indeterminé : cela peut ne pas être pas nécessaire d'intercaler des caractères avant le _n_
ou cela peut être nécessaire d'en intercepter plusieurs :

```{python}
Expand Down Expand Up @@ -792,7 +792,7 @@ data_books.loc[~(data_books['Date of Publication'] == data_books['year']), ['Dat
```

Quant aux nouveaux `NaN`,
il s'agit de lignes qui ne contenaient pas de chaînes de caractères qui ressemblaient à des années:
il s'agit de lignes qui ne contenaient pas de chaînes de caractères qui ressemblaient à des années :

```{python}
#| echo: false
Expand Down
2 changes: 1 addition & 1 deletion content/manipulation/04c_API_TP.qmd
Expand Up @@ -283,7 +283,7 @@ def interactive_map_dpe(dpe):
# I can add marker one by one on the map
for i in range(0,len(dpe)):
folium.Marker([dpe.iloc[i]['latitude'], dpe.iloc[i]['longitude']],
popup=f"Année de construction: {dpe.iloc[i]['annee_construction']}, <br>DPE: {dpe.iloc[i]['classe_consommation_energie']}",
popup=f"Année de construction : {dpe.iloc[i]['annee_construction']}, <br>DPE : {dpe.iloc[i]['classe_consommation_energie']}",
icon=folium.Icon(color="black", icon="home", icon_color = dpe.iloc[i]['color'])).add_to(m)
m.fit_bounds([sw, ne])
Expand Down
74 changes: 63 additions & 11 deletions content/modelisation/0_preprocessing.qmd
Expand Up @@ -60,7 +60,7 @@ pas négliger. Les modèles reposent sur certaines hypothèses, généralement
relatives à la distribution théorique des variables qui y sont intégrées.

Il est nécessaire de faire correspondre la distribution empirique
à ces hypothèses ce qui implique un travail de restructuration des données.
à ces hypothèses, ce qui implique un travail de restructuration des données.
Celui-ci permettra d'avoir des résultats de modélisation plus pertinents.
Nous verrons dans le chapitre sur les *pipelines* comment industrialiser
ces étapes de _preprocessing_ afin de se simplifier la vie pour appliquer
Expand All @@ -79,7 +79,7 @@ Cet aspect unifié est l'une des raisons du succès précoce de celle-ci. `R` n'
bénéficié que plus récemment d'une librairie unifiée,
à savoir [`tidymodels`](https://www.tidymodels.org/).

Une autre raison du succès de `scikit` est son approche opérationnelle: la mise
Une autre raison du succès de `scikit` est son approche opérationnelle : la mise
en production de modèles développés via les _pipelines_ `scikit` est peu coûteuse.
Un [chapitre spécial de ce cours](/pipeline-scikit) est dédié aux _pipelines_.
Avec Romain Avouac, nous proposons un [cours plus avancé](https://ensae-reproductibilite.github.io/website/)
Expand All @@ -99,7 +99,7 @@ développé dans le cadre de l'initiative [`Inria Academy`](https://www.inria.fr
:::

Les _packages_ suivants sont nécessaires pour importer et visualiser
les données d'élection:
les données d'élection :

```{python}
#| eval: false
Expand All @@ -116,7 +116,7 @@ pour produire des analyses valides scientifiquement.

La démarche générale que nous adopterons dans ce chapitre, et
qui sera ensuite raffinée dans les prochains chapitres,
est la suivante:
est la suivante :

![](scikit_predict.png)

Expand Down Expand Up @@ -197,7 +197,7 @@ votes = getdata.create_votes_dataframes()

Ce code introduit une base nommée `votes` dans l'environnement. Il s'agit d'une
base rassemblant les différentes sources. Elle a l'aspect
suivant:
suivant :

```{python}
#| echo: true
Expand Down Expand Up @@ -252,7 +252,7 @@ l'une des surcouches à `JavaScript` vues dans la partie [visualisation](#visual

En l'occurrence, on peut utiliser `Plotly` pour tenir compte de la population
et faire une carte en ronds proportionnels.
Le code suivant permet de construire une carte adaptée:
Le code suivant permet de construire une carte adaptée :

```{python}
#| output: false
Expand Down Expand Up @@ -350,7 +350,7 @@ ainsi que les relations entre les variables explicatives.
`Median_Household_Income_2019`,
`Percent of adults with less than a high school diploma, 2015-19`,
`Percent of adults with a bachelor's degree or higher, 2015-19`
2. Représenter grâce à un graphique la matrice de corrélation. Vous pouvez utiliser le _package_ `seaborn` et sa fonction `seaborn`.
2. Représenter grâce à un graphique la matrice de corrélation. Vous pouvez utiliser le _package_ `seaborn` et sa fonction `heatmap`.
3. Représenter une matrice de nuages de points des variables de la base `df2` avec `pd.plotting.scatter_matrix`
4. (optionnel) Refaire ces figures avec `Plotly` qui offre également la possibilité de faire une matrice de corrélation.

Expand Down Expand Up @@ -406,7 +406,7 @@ Le résultat de la question 4 devrait, quant à lui,
ressembler au graphique suivant :

```{python}
# 4. Matrice de corélation avec plotly
# 4. Matrice de corrélation avec plotly
import plotly
import plotly.express as px
htmlsnip2 = px.scatter_matrix(df2)
Expand All @@ -423,11 +423,11 @@ diverger des hypothèses sous-jacentes dans les modèles.
Par exemple, dans le cadre
de la régression linéaire, les variables catégorielles ne sont pas traitées à la même
enseigne que les variables ayant valeur dans $\mathbb{R}$. Une variable
discrète (prenant un nombre fini de valeurs) devra être transformées en suite de
discrète (prenant un nombre fini de valeurs) devra être transformée en suite de
variables 0/1 par rapport à une modalité de référence pour être en adéquation
avec les hypothèses de la régression linéaire.
On appelle ce type de transformation
*one-hot encoding*, sur lequel nous reviendrons. Il s'agit d'une transformation,
*one-hot encoding*, sur laquelle nous reviendrons. Il s'agit d'une transformation,
parmi d'autres, disponibles dans `scikit` pour mettre en adéquation un jeu de
données et des hypothèses mathématiques.

Expand All @@ -438,7 +438,7 @@ consiste à apprendre des paramètres d'une structure
de données (par exemple estimer moyennes et variances pour les retrancher à chaque
observation) et on peut très bien appliquer ces paramètres
à des observations qui n'ont pas servi à construire
ceux-ci. Ainsi, en gardant en tête l'approche générale avec `Scikit`
ceux-ci. Ainsi, en gardant en tête l'approche générale avec `Scikit`,

![](scikit_predict.png)

Expand Down Expand Up @@ -592,7 +592,51 @@ il convient de retirer une modalité avant l'estimation.
* `OneHotEncoder` est une version généralisée (et optimisée) de la *dummy expansion*.
Il a plutôt vocation à s'appliquer sur les *features* ($X$) du modèle

### Imputation

Les données peuvent souvent contenir des valeurs manquantes, autrement dit des cases de notre _DataFrame_ contenant un `NaN`.
Ces trous dans les données peuvent être à l'origine de _bugs_ ou de mauvaises interprétations lorsque l'on passe à la modélisation.
Pour y remédier, une première approche peut être de retirer toutes les observations présentant un `NaN` dans au moins l'une des colonnes.
Cependant, si notre table contient beaucoup de `NaN`, ou bien que ces derniers sont répartis sur de nombreuses colonnes,
c'est aussi prendre le risque de retirer un nombre important de lignes, et avec cela de l'information importante pour un modèle car les valeurs manquantes sont rarement [réparties de manière aléatoire](https://stefvanbuuren.name/fimd/sec-MCAR.html).

Même si dans plusieurs situations, cette solution reste tout à fait viable, il existe une autre approche plus robuste appelée *imputation*.
Cette méthode consiste à remplacer les valeurs vides par une valeur donnée. Par exemple :

- Imputation par la moyenne : remplacer tous les `NaN` dans une colonne par la valeur moyenne de la colonne ;
- Imputation par la médiane sur le même principe, ou par la valeur de la colonne la plus fréquente pour les variables catégorielles ;
- Imputation par régression : se servir d'autres variables pour essayer d'interpoler une valeur de remplacement adaptée.

Des méthodes plus complexes existent, mais dans de nombreux cas,
les approches ci-dessus peuvent suffire pour donner des résultats beaucoup plus satisfaisants.
Le package `Scikit` permet de faire de l'imputation de manière très simple ([documentation ici](https://scikit-learn.org/stable/modules/impute.html)).

### Gestion des outliers


Les valeurs aberrantes (_outliers_ en anglais) sont des observations qui se situent significativement à l'extérieur de la tendance générale des autres observations dans un ensemble de données. En d'autres termes, ce sont des points de données qui se démarquent de manière inhabituelle par rapport à la distribution globale des données.
Cela peut être dû à des erreurs de remplissage, des personnes ayant mal répondu à un questionnaire, ou
parfois simplement des valeurs extrêmes qui peuvent biaiser un modèle de façon trop importante.

A titre d'exemple, cela va être 3 individus mesurant plus de 4 mètres dans une population,
ou bien des revenus de ménage dépassant les 10M d'euros par mois sur l'échelle d'un pays, etc.

Une bonne pratique peut donc être de systématiquement regarder la distribution des variables à disposition,
pour se rendre compte si certaines valeurs s'éloignent de façon trop importante des autres.
Ces valeurs vont parfois nous intéresser, si par exemple on se concentre uniquement sur les très hauts revenus (top 0.1%)
en France. Cependant, ces données vont souvent nous gêner plus qu'autre chose, surtout si elles n'ont pas de sens dans le monde réel.

Si l'on estime que la présence de ces données extrêmes, ou *outliers*, dans notre base de données vont être problématiques plus qu'autre chose,
alors il est tout à fait entendable et possible de simplement les retirer.
La plupart du temps, on va se donner une proportion des données à retirer, par exemple 0.1%, 1% ou 5%,
puis retirer dans les deux queues de la distribution les valeurs extrêmes correspondantes.

Plusieurs packages permettent de faire ce type d'opérations, qui sont parfois plus complexes si on s'intéresse aux outlier sur plusieurs variables.
On pourra notamment citer la fonction `IsolationForest()` du package `sklearn.ensemble`.

<br>

Pour plus de détails sur ces deux derniers points, il est recommandé d'aller voir l'exemple *Pour aller plus loin* en bas de la page.

::: {.cell .markdown}
```{=html}
Expand Down Expand Up @@ -652,6 +696,14 @@ onehot_enc = preprocessing.OneHotEncoder().fit(df)
onehot_enc.transform(df)
```

## Pour aller plus loin : un exemple pratique

Pour faire vos premiers pas en modélisation, notamment sur le preprocessing de données, vous pouvez également consulter le sujet 3 d'un hackathon organisé par l'Insee en 2023, *Explorer les habitudes alimentaires de nos compatriotes*, sur le [SSP Cloud](https://www.sspcloud.fr/formation?search=funath&path=%5B%22Funathon%202023%22%5D) ou sur [Github](https://github.com/InseeFrLab/funathon2023_sujet3/).

Le but du sujet est de travailler sur les données de consommations et habitudes alimentaires de l'étude INCA 3. Vous y travaillerez plusieurs thèmes :
- Analyse exploratoire de données et visualisations
- Clustering d'individus : du preprocessing jusqu'aux méthodes classiques d'apprentissage non supervisé (ACP, K-moyennes, Clustering Ascendant Hiérarchique)
- Prédiction de l'IMC : Premiers pas vers les méthodes d'apprentissage supervisé et les _preprocessings_ associés

## Références

Expand Down

0 comments on commit a06a268

Please sign in to comment.