diff --git a/content/course/manipulation/02a_pandas_tutorial.Rmd b/content/course/manipulation/02a_pandas_tutorial.Rmd index c2bc9f47e..ca9a1fa6f 100644 --- a/content/course/manipulation/02a_pandas_tutorial.Rmd +++ b/content/course/manipulation/02a_pandas_tutorial.Rmd @@ -75,10 +75,20 @@ Dans ce tutoriel `pandas`, nous allons utiliser: * Les émissions de gaz à effet de serre estimées au niveau communal par l'ADEME. Le jeu de données est disponible sur [data.gouv](https://www.data.gouv.fr/fr/datasets/inventaire-de-gaz-a-effet-de-serre-territorialise/#_) -et requêtable directement dans python avec +et requêtable directement dans `Python` avec [cet url](https://koumoul.com/s/data-fair/api/v1/datasets/igt-pouvoir-de-rechauffement-global/convert) -* Quelques données de contexte au niveau communal. Idéalement, on utiliserait les données -[disponibles sur le site de l'Insee](https://www.insee.fr/fr/statistiques/3560121). Pour faciliter l'import de celles-ci, les données ont été mises à disposition dans le dépôt github, [sur cet url](https://github.com/linogaliana/python-datascientist/blob/pandas_intro/data/filosofi_2016.csv) + +Le chapitre suivant permettra de mettre en application des éléments présents dans ce chapitre avec +les données ci-dessus associées à des données de contexte au niveau communal[^1]. + + +[^1]: Idéalement, on utiliserait les données +[disponibles sur le site de l'Insee](https://www.insee.fr/fr/statistiques/3560121) mais celles-ci nécessitent un peu de travail +de nettoyage qui n'entre pas dans le cadre de ce TP. +Pour faciliter l'import de données Insee, il est recommandé d'utiliser le package +[`pynsee`](https://github.com/InseeFrLab/Py-Insee-Data) qui simplifie l'accès aux données +de l'Insee disponibles sur le site web [insee.fr](https://www.insee.fr/fr/accueil) +ou via des API. :warning: `pandas` offre la possibilité d'importer des données @@ -94,6 +104,7 @@ Nous suivrons les conventions habituelles dans l'import des packages import numpy as np import pandas as pd import matplotlib.pyplot as plt +import pynsee.download ``` Pour obtenir des résultats reproductibles, on peut fixer la racine du générateur @@ -456,7 +467,7 @@ Voici un premier résumé des méthodes `pandas` utiles, et un comparatif avec ` | Récupérer les dimensions | `df.shape` | `c(nrow(df), ncol(df))` | `c(nrow(df), ncol(df))` | | Récupérer le nombre de valeurs uniques d'une variable | `df['myvar'].nunique()` | `df %>% summarise(distinct(myvar))` | `df[,uniqueN(myvar)]` | -^[3]: Le principe d'indice n'existe pas dans `dplyr`. Ce qui s'approche le plus des indices, au sens de +[^3]: Le principe d'indice n'existe pas dans `dplyr`. Ce qui s'approche le plus des indices, au sens de `pandas`, sont les *clés* en `data.table`. @@ -535,7 +546,7 @@ On trouvera aussi la référence à `isna()` qui est la même méthode que `isnu # Graphiques rapides Les méthodes par défaut de graphique -(approfondies dans la partie visualisation **LIEN A AJOUTER**) +(approfondies dans la [partie visualisation](#visualisation)) sont pratiques pour produire rapidement un graphique, notament après des opérations complexes de maniement de données. @@ -756,7 +767,7 @@ résidentiel consomme le plus. ## Filtrer -L'opération de sélection de lignes s'appelle `FILTER` en SQL et s'utilise +L'opération de sélection de lignes s'appelle `FILTER` en SQL. Elle s'utilise en fonction d'une condition logique (clause `WHERE`). On sélectionne les données sur une condition logique. Il existe plusieurs méthodes en `pandas`. @@ -860,7 +871,7 @@ du DataFrame de sortie. Si on avait utilisé plusieurs variables de groupe, on obtiendrait un objet multi-indexé. Sur la gestion des `multiindex`, on pourra se référer à la référence de `Modern pandas` donnée en fin de cours. -Tant qu'on appelle pas une action sur un DataFrame par groupe, du type +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: @@ -940,7 +951,7 @@ serions dans une situation, beaucoup plus complexe, d'appariement flou). La situation typique est l'appariement entre deux sources de données selon un identifiant individuel. Ici, il s'agit d'un identifiant de code commune. -Il est recommandé de lire [ce guide assez complet sur la question des jointures avec R](https://linogaliana.gitlab.io/documentationR/joindre-des-tables-de-donn%C3%A9es.html) qui donne des recommandations également utiles en `python`. +Il est recommandé de lire [ce guide assez complet sur la question des jointures avec R](https://www.book.utilitr.org/jointures.html) qui donne des recommandations également utiles en `python`. On utilise de manière indifférente les termes *merge* ou *join*. Le deuxième terme provient de la syntaxe SQL. diff --git a/content/course/manipulation/02b_pandas_TP.Rmd b/content/course/manipulation/02b_pandas_TP.Rmd index ba098ef4a..5af58a8fe 100644 --- a/content/course/manipulation/02b_pandas_TP.Rmd +++ b/content/course/manipulation/02b_pandas_TP.Rmd @@ -37,16 +37,12 @@ knitr::opts_chunk$set(echo = FALSE) ``` -Dans ce tutoriel `pandas`, nous allons utiliser: +Dans ce tutoriel `pandas`, nous allons utiliser deux sources de données : * Les émissions de gaz à effet de serre estimées au niveau communal par l'ADEME. Le jeu de données est disponible sur [data.gouv](https://www.data.gouv.fr/fr/datasets/inventaire-de-gaz-a-effet-de-serre-territorialise/#_) et requêtable directement dans python avec [cet url](https://koumoul.com/s/data-fair/api/v1/datasets/igt-pouvoir-de-rechauffement-global/convert) -* Quelques données de contexte au niveau communal. Idéalement, on utiliserait les données -[disponibles sur le site de l'Insee](https://www.insee.fr/fr/statistiques/3560121). Pour faciliter l'import de celles-ci, les données ont été mises à disposition dans le dépôt github, [sur cet url](https://github.com/linogaliana/python-datascientist/blob/pandas_intro/data/filosofi_2016.csv) - - `pandas` offre la possibilité d'importer des données directement depuis un url. C'est l'option prise dans ce tutoriel. Si vous préfèrez, pour des @@ -54,13 +50,34 @@ raisons d'accès au réseau ou de performance, importer depuis un poste local, vous pouvez télécharger les données et changer les commandes d'import avec le chemin adéquat plutôt que l'url. +* Idéalement, on utiliserait les données +[disponibles sur le site de l'Insee](https://www.insee.fr/fr/statistiques/3560121) mais celles-ci nécessitent un peu de travail +de nettoyage qui n'entre pas dans le cadre de ce TP. +Pour faciliter l'import de données Insee, il est recommandé d'utiliser le package +[`pynsee`](https://github.com/InseeFrLab/Py-Insee-Data) qui simplifie l'accès aux données +de l'Insee disponibles sur le site web [insee.fr](https://www.insee.fr/fr/accueil) +ou via des API. + +{{% panel status="note" title="Note" icon="fa fa-comment" %}} +Pour installer `pynsee` depuis le [dépôt Github](https://github.com/InseeFrLab/Py-Insee-Data), il est nécessaire +de taper, dans une invite de commande, + +```shell +pip install git+https://github.com/InseeFrLab/Py-Insee-Data@master +``` + +{{% /panel %}} + +[^1]: Toute contribution sur ce package, disponible sur [Github](https://github.com/InseeFrLab/Py-Insee-Data) est bienvenue ! + Nous suivrons les conventions habituelles dans l'import des packages -```{python} +```{python, echo = TRUE} import numpy as np import pandas as pd import matplotlib.pyplot as plt +import pynsee.download ``` ## Exploration de la structure des données @@ -71,13 +88,17 @@ Commencer par importer les données de l'Ademe à l'aide du package `pandas`. Vo df = pd.read_csv("https://koumoul.com/s/data-fair/api/v1/datasets/igt-pouvoir-de-rechauffement-global/convert") ``` -Pour les données de cadrage au niveau communal (source Insee), une version arrangée et facile à requêter est fournie sur [github](https://github.com/linogaliana/python-datascientist/blob/pandas_intro/data/filosofi_2016.csv) +Pour les données de cadrage au niveau communal (source Insee), le package `pynsee` facilite grandement la vie. +La liste des données disponibles est [ici](https://inseefrlab.github.io/DoReMIFaSol/articles/donnees_dispo.html). +En l'occurrence, on va utiliser les données Filosofi (données de revenu) au niveau communal. +Le code pour télécharger celle-ci est le suivant -```{python} -df_city = pd.read_csv("https://raw.githubusercontent.com/linogaliana/python-datascientist/master/data/filosofi_2016.csv") +```{python, echo = TRUE} +df_city = pynsee.download.telechargerDonnees("FILOSOFI_COM", date = "dernier") ``` ------------------ +{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}} + **Exercice 1: Afficher des données** L'objectif de cet exercice est de vous amener à afficher des informations sur les données dans un bloc de code (notebook) ou dans la console @@ -91,7 +112,8 @@ Commencer sur `df`: Faire la même chose sur `df_city` ------------------- +{{% /panel %}} + ```{python, show = FALSE, include = FALSE} df.head(10) @@ -114,7 +136,8 @@ df_city[:6].sample(n = 100, replace = True, weights = [0.5] + [0.1]*5) Cette première approche exploratoire donne une idée assez précise de la manière dont les données sont organisées. On remarque ainsi une différence entre `df` et `df_city` quant aux valeurs manquantes: la première base est relativement complète, la seconde comporte beaucoup de valeurs manquantes. Autrement dit, si on désire exploiter `df_city`, il faut faire attention à la variable choisie. ----------------------- +{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}} + **Exercice 2: structure des données** La première chose à vérifier est le format des données, afin d'identifier des types de variables qui ne conviennent pas. Ici, comme c'est `pandas` qui a géré automatiquement les types de variables, il y a peu de chances que les types ne soient pas adéquats mais une vérification ne fait pas de mal. @@ -135,7 +158,8 @@ On se focalise temporairement sur les observations où le libellé comporte plus * Vérifier sur les grandes villes (plus de 100 000 personnes), la proportion de villes où libellés et codes communes ne coïncident pas. Identifier ces observations. * Vérifier dans `df_city` les villes dont le libellé est égal à Montreuil. Vérifier également celles qui contiennent le terme 'Saint-Denis' ------------------------ +{{% /panel %}} + ```{python, include = FALSE, eval = FALSE} df.dtypes @@ -187,7 +211,8 @@ Ce petit exercice permet de se rassurer car les libellés dupliqués sont en fai Les indices sont des éléments spéciaux d'un DataFrame puisqu'ils permettent d'identifier certaines observations. Il est tout à fait possible d'utiliser plusieurs indices, par exemple si on a des niveaux imbriqués. ----------------------- +{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}} + **Exercice 3: Les indices** A partir de l'exercice précédent, on peut se fier aux codes communes. @@ -197,7 +222,8 @@ A partir de l'exercice précédent, on peut se fier aux codes communes. * Calculer les émissions totales par secteur pour chaque département. Mettre en log ces résultats dans un objet `df_log`. Garder 5 départements et produire un barplot * Repartir de `df`. Calculer les émissions totales par département et sortir la liste des 10 principaux émetteurs de CO2 et des 5 départements les moins émetteurs. Sans faire de *merge*, regarder les caractéristiques de ces départements (population et niveau de vie) -------------------------- +{{% /panel %}} + ```{python, include = FALSE, eval = FALSE} df = df.set_index('INSEE commune') @@ -234,7 +260,8 @@ df_city[df_city['dep'].isin(petits_emetteurs.index)][['NBPERSMENFISC16','MED16'] df_city[df_city['dep'].isin(petits_emetteurs.index)][['NBPERSMENFISC16','MED16']].mean() ``` -------------------------- +{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}} + **Exercice 4: performance des indices** Un des intérêts des indices est qu'il permettent des agrégations efficaces. @@ -243,7 +270,8 @@ Un des intérêts des indices est qu'il permettent des agrégations efficaces. * Utiliser la variable `dep` comme indice pour `df_copy` et retirer tout index pour `df_copy2` * Importer le module `timeit` et comparer le temps d'exécution de la somme par secteur, pour chaque département, des émissions de CO2 ---------------------------- +{{% /panel %}} + ```{python, include = FALSE, eval = FALSE} df_copy = df.copy() @@ -280,7 +308,8 @@ L'aide mémoire suivante aidera à se rappeler les fonctions à appliquer si bes Le fait de passer d'un format *wide* au format *long* (ou vice-versa) peut être extrêmement pratique car certaines fonctions sont plus adéquates sur une forme de données ou sur l'autre. En règle générale, avec `python` comme avec `R`, les formats *long* sont souvent préférables. ----------------------------- +{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}} + **Exercice 5: Restructurer les données: wide to long** * Créer une copie des données de l'ADEME en faisant `df_wide = df.copy()` @@ -288,7 +317,8 @@ Le fait de passer d'un format *wide* au format *long* (ou vice-versa) peut être * Faire la somme par secteur et représenter graphiquement * Garder, pour chaque département, le secteur le plus polluant --------------------------------- +{{% /panel %}} + ```{python, include = FALSE, eval = FALSE} @@ -306,7 +336,8 @@ df_wide.reset_index().melt(id_vars = ['INSEE commune','Commune','dep'], ) ``` ------------------------------------ +{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}} + **Exercice 6: long to wide** Cette transformation est moins fréquente car appliquer des fonctions par groupe, comme nous le verrons par la suite, est très simple. @@ -317,7 +348,8 @@ Cette transformation est moins fréquente car appliquer des fonctions par groupe * Calculer, pour chaque secteur, la place du département dans la hiérarchie des émissions nationales * A partir de là, en déduire le rang médian de chaque département dans la hiérarchie des émissions et regarder les 10 plus mauvais élèves, selon ce critère. ---------------------------------- +{{% /panel %}} + ```{python, include = FALSE, eval = FALSE} df_wide = df.copy() @@ -339,7 +371,9 @@ On utilise de manière indifférente les termes *merge* ou *join*. Le deuxième ![](../02a_pandas_tutorial/pandas_join.png) ------------------------------------- + +{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}} + **Exercice 7: Calculer l'empreinte carbone par habitant** * Créer une variable `emissions` qui correspond aux émissions totales d'une commune @@ -347,7 +381,8 @@ On utilise de manière indifférente les termes *merge* ou *join*. Le deuxième * Faire un *inner join* puis calculer l'empreinte carbone dans chaque commune. Sortir un histogramme en niveau puis en log et quelques statistiques descriptives sur le sujet. * Regarder la corrélation entre les variables de cadrage et l'empreinte carbone. Certaines variables semblent expliquer l'empreinte carbone ? --------------------------------------------- +{{% /panel %}} + ```{python, include = FALSE, eval = FALSE} df['emissions'] = df.sum(axis = 1)