diff --git a/.github/workflows/netlify-test.yaml b/.github/workflows/netlify-test.yaml index 37ac47e50..b7ead9ecf 100644 --- a/.github/workflows/netlify-test.yaml +++ b/.github/workflows/netlify-test.yaml @@ -28,7 +28,7 @@ jobs: quarto render --to html - name: Install npm if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: '18' - name: Deploy to Netlify diff --git a/content/modelisation/5_clustering.qmd b/content/modelisation/5_clustering.qmd index 968de95c1..f18c5d30e 100644 --- a/content/modelisation/5_clustering.qmd +++ b/content/modelisation/5_clustering.qmd @@ -30,20 +30,8 @@ echo: false --- -::: {.cell .markdown} -```{python} -#| echo: false -#| output: 'asis' -#| include: true -#| eval: true - -import sys -sys.path.insert(1, '../../') #insert the utils module -from utils import print_badges - -#print_badges(__file__) -print_badges("content/modelisation/5_clustering.qmd") -``` +::: {.content-visible when-format="html"} +{{< include "../../build/_printBadges.qmd" >}} ::: @@ -51,6 +39,15 @@ print_badges("content/modelisation/5_clustering.qmd") {{< include _import_data_ml.qmd >}} +Il peut également être utile d'installer `plotnine` +pour réaliser des graphiques simplement: + +```{python} +#| echo: true +#| output: false +!pip install plotnine +``` + ## Introduction sur le *clustering* @@ -174,9 +171,9 @@ import seaborn as sns #pour scatterplots 3. Créer une variable `label` dans `votes` stockant le résultat de la typologie 4. Afficher cette typologie sur une carte. 5. Choisir les variables `Median_Household_Incomme_2019` et `Unemployment_rate_2019` et représenter le nuage de points en colorant différemment -en fonction du label obtenu. - -6. Représenter la distribution du vote pour chaque *cluster* +en fonction du label obtenu. Quel est le problème ? +6. Refaire les questions 2 à 5 en standardisant les variables en amont +7. Représenter la distribution du vote pour chaque *cluster* ```{=html} @@ -238,40 +235,113 @@ et `Unemployment_rate_2019`, aura l'aspect suivant : ```{python} #| output: false +from plotnine import * + #5. Nuage de points de 2 variables et coloration selon le label -plt.figure() -p = sns.scatterplot( - data=votes, - x="Median_Household_Income_2019", - y="Unemployment_rate_2019", hue = "label", palette="deep", - alpha = 0.4) -p.set(xscale="log") +votes['label'] = pd.Categorical(votes['label']) +p = ( + ggplot(votes) + + geom_point( + aes( + x = "Median_Household_Income_2019", + y = "Unemployment_rate_2019", + color = "label" + ), + alpha = 0.4 + ) + + theme_bw() + scale_x_log10() +) ``` ```{python} -#| echo: false -p.figure.get_figure() +p ``` ```{python} #| output: false -p.figure.get_figure().savefig("featured_clustering.png") +ggsave(p, "featured_clustering.png") +``` + +La classification apparaît un peu trop nettement dans cette figure. +Cela suggère que la variable de revenu (`Median_Household_Income_2019`) +explique un peu trop bien le partitionnement produit par notre +modèle pour que ce soit normal. C'est probablement le fait +de la variance forte du revenu par rapport aux autres variables. +Dans ce type de sitution, comme cela a été évoqué, il est +recommandé de standardiser les variables. + + +```{python} +from sklearn.preprocessing import StandardScaler +from sklearn.pipeline import make_pipeline + +kmeans = make_pipeline( + StandardScaler(), + KMeans(n_clusters=4, random_state=123) +) +kmeans.fit(df2) + +votes['label'] = kmeans.predict(df2) + +p = votes.plot(column = "label", cmap = "inferno") +p.set_axis_off() ``` -Enfin, l'histogramme des votes pour chaque cluster est : +On obtient ainsi la carte suivante à la question 5: + +```{python} +p.get_figure() +``` + +Et le nuage de point de la question 5 présente un aspect moins +déterministe, ce qui est préférable : + +```{python} +from plotnine import * +from mizani.formatters import percent_format + +votes['label'] = pd.Categorical(votes['label']) + +( + ggplot(votes) + + geom_point( + aes( + x = "Median_Household_Income_2019/1000", + y = "Unemployment_rate_2019/100", + color = "label" + ), + alpha = 0.4 + ) + + theme_bw() + scale_x_log10() + + scale_y_continuous(labels=percent_format()) + + labs( + x = "Revenu médian du comté (milliers de $)", + y = "Taux de chômage du comté") +) +``` + + +Enfin, en ce qui concerne la question 6, on obtient cet +histogramme des votes pour chaque cluster : ```{python} #| output: false # 6. Distribution du vote selon chaque cluster plt.figure() -p2 = sns.displot(data=votes, x="per_gop", hue="label", alpha = 0.4) +p2 = ( + ggplot(votes) + + geom_histogram( + aes(x = "per_gop", fill = "label"), alpha = 0.2, position="identity" + ) + + theme_minimal() +) ``` ```{python} #| echo: false -p2.figure.get_figure() +p2 ``` @@ -505,4 +575,7 @@ Pour mettre en pratique les méthodes de création de clusters, de la base brute ### Pour la réduction de dimension L'ACP est également très utile dans le champ de la réduction du nombre de variables pour de nombreux types de modélisations, comme par exemple les régressions linéaires. -Il est ainsi possible de projeter l'espace des variables explicatives dans un espace de dimension donnée plus faible, pour notamment limiter les risques d'overfitting. +Il est ainsi possible de projeter l'espace des variables explicatives dans un espace de dimension donnée plus faible, pour notamment limiter les risques d'_overfitting_. + + +## Références {-} \ No newline at end of file diff --git a/content/modelisation/_import_data_ml.qmd b/content/modelisation/_import_data_ml.qmd index b21f947f0..4c800987a 100644 --- a/content/modelisation/_import_data_ml.qmd +++ b/content/modelisation/_import_data_ml.qmd @@ -12,7 +12,6 @@ est disponible [sur Github](https://github.com/linogaliana/python-datascientist/ !pip install geopandas ``` -::: {.python} ```{python} #| echo: true #| output: false @@ -26,5 +25,4 @@ open('getdata.py', 'wb').write(r.content) import getdata votes = getdata.create_votes_dataframes() ``` -:::