Les exemples de ce TP sont visualisables sous forme de Jupyter Notebooks
:
Dans cette série d’exercices Pandas
,
nous allons découvrir comment manipuler plusieurs
jeux de données avec Python
.
Si vous êtes intéressés par R
,
une version très proche de ce TP est
disponible dans ce cours.
Dans ce tutoriel, 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 et requêtable directement dansPython
avec cet url (ce sera l’objet du premier exercice). - Idéalement, on utiliserait directement les données
disponibles sur le site de l’Insee 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
qui simplifie l’accès aux données de l’Insee disponibles sur le site web insee.fr ou via des API. - Le premier exercice présentera le code officiel géographique, un référentiel produit par l’Insee utilisé pour identifier les communes à partir d’un code unique, contrairement au code postal.
La librairie pynsee
n’est pas installée par défaut avec Python
. Avant de pouvoir l’utiliser,
il est nécessaire de l’installer :
!pip install xlrd
!pip install pynsee
!pip install great_tables
Toutes les dépendances indispensables étant installées, il suffit maintenant d’importer les librairies qui seront utilisées pendant ces exercices :
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pynsee
import pynsee.download
1 Importer les données
1.1 Lire des données depuis un chemin local
Cet exercice vise à présenter l’intérêt d’utiliser un chemin relatif plutôt qu’un chemin absolu.
Pour préparer cet exercice, le code suivant permettra de télécharger des données qu’on va écrire en local
import requests
= "https://www.insee.fr/fr/statistiques/fichier/6800675/v_commune_2023.csv"
url = requests.get(url)
response
# Assurez-vous que la requête a réussi
if response.status_code == 200:
with open("cog_2023.csv", "wb") as file:
file.write(response.content)
else:
print("Échec du téléchargement du fichier. Statut HTTP :", response.status_code)
Exercice préliminaire: Importer un CSV (optionnel)
- Utiliser le code ci-dessus ☝️ pour télécharger les données. Utiliser
Pandas
pour lire le fichier téléchargé. - Chercher où les données ont été écrites. Observer la structure de ce dossier.
- Créer un dossier depuis l’explorateur de fichiers (à gauche dans
Jupyter
ouVSCode
). Déplacer le CSV et le notebook. Redémarrer le kernel et adaptez votre code si besoin. Refaire cette manipulation plusieurs fois avec des dossiers différents. Quel peut être le problème rencontré ?
TYPECOM | COM | REG | DEP | CTCD | ARR | TNCC | NCC | NCCENR | LIBELLE | CAN | COMPARENT | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | COM | 01001 | 84.0 | 01 | 01D | 012 | 5 | ABERGEMENT CLEMENCIAT | Abergement-Clémenciat | L'Abergement-Clémenciat | 0108 | NaN |
1 | COM | 01002 | 84.0 | 01 | 01D | 011 | 5 | ABERGEMENT DE VAREY | Abergement-de-Varey | L'Abergement-de-Varey | 0101 | NaN |
1.2 Importer et découvrir des données depuis un CSV
Il est plus pratique lorsque le CSV est disponible directement depuis un lien HTTPS de lire directement les données avec Pandas
, sans passer par l’écriture d’un fichier en local. Cela permet de limiter les problèmes d’adhérance à un file system.
L’URL d’accès aux données peut être conservé dans une variable ad hoc :
= "https://koumoul.com/s/data-fair/api/v1/datasets/igt-pouvoir-de-rechauffement-global/convert" url
Et utilisé ensuite pour la lecture des données.
L’objectif du premier exercice est de se familiariser à l’import et l’affichage de données
avec Pandas
.
Exercice 1: Importer un CSV et explorer la structure de données
- Importer les données de l’Ademe à l’aide du package
Pandas
et de la commande consacrée pour l’import de csv. Nommer leDataFrame
obtenuemissions
1. - Utiliser les méthodes adéquates afin d’afficher pour les 10 premières valeurs, les 15 dernières et un échantillon aléatoire de 10 valeurs grâce aux méthodes adéquates du package
Pandas
. - Tirer 5 pourcents de l’échantillon sans remise.
- Ne conserver que les 10 premières lignes et tirer aléatoirement dans celles-ci pour obtenir un DataFrame de 100 données.
- Faire 100 tirages à partir des 6 premières lignes avec une probabilité de 1/2 pour la première observation et une probabilité uniforme pour les autres.
En cas de blocage à la question 1
Lire la documentation de read_csv
(très bien faite) ou chercher des exemples
en ligne pour découvrir cette fonction.
2 Premières manipulations de données
Le chapitre précédent évoquait quelques manipulations traditionnelles de données. Les principales sont rappelées ici :
La cheatsheet suivante est très pratique puisqu’elle illustre ces différentes fonctions. Il est recommandé de régulièrement la consulter :
L’objectif du prochain exercice est de se familiariser aux principales manipulations de données sur un sous-ensemble de la table des émissions de gaz carbonique.
Exercice 2: Découverte des verbes de Pandas
pour manipuler des données
En premier lieu, on propose de se familiariser avec les opérations sur les colonnes.
- Créer un dataframe
emissions_copy
ne conservant que les colonnesINSEE commune
,Commune
,Autres transports
etAutres transports international
- Comme les noms de variables sont peu pratiques, les renommer de la
manière suivante :
INSEE commune
\(\to\)code_insee
Autres transports
\(\to\)transports
Autres transports international
\(\to\)transports_international
On propose, pour simplifier, de remplacer les valeurs manquantes (
NA
) par la valeur 0. Utiliser la méthodefillna
pour transformer les valeurs manquantes en 0.Créer les variables suivantes :
dep
: le département. Celui-ci peut être créé grâce aux deux premiers caractères decode_insee
en appliquant la méthodestr
;transports_total
: les émissions du secteur transports (somme des deux variables)
- Ordonner les données du plus gros pollueur au plus petit puis ordonner les données du plus gros pollueur au plus petit par département (du 01 au 95).
- Ne conserver que les communes appartenant aux départements 13 ou 31. Ordonner ces communes du plus gros pollueur au plus petit.
- Calculer les émissions totales par départements
Indice pour cette question
- “Grouper par” =
groupby
- “émissions totales” =
agg({*** : "sum"})
A la question 5, quand on ordonne les communes exclusivement à partir de la variable
transports_total
, on obtient ainsi:
code_insee | Commune | transports | transports_international | dep | transports_total | |
---|---|---|---|---|---|---|
31108 | 77291 | LE MESNIL-AMELOT | 133834.090767 | 3.303394e+06 | 77 | 3.437228e+06 |
31099 | 77282 | MAUREGARD | 133699.072712 | 3.303394e+06 | 77 | 3.437093e+06 |
31111 | 77294 | MITRY-MORY | 89815.529858 | 2.202275e+06 | 77 | 2.292090e+06 |
A la question 6, on obtient ce classement :
code_insee | Commune | transports | transports_international | dep | transports_total | |
---|---|---|---|---|---|---|
4438 | 13096 | SAINTES-MARIES-DE-LA-MER | 271182.758578 | 0.000000 | 13 | 271182.758578 |
4397 | 13054 | MARIGNANE | 245375.418650 | 527360.799265 | 13 | 772736.217915 |
11684 | 31069 | BLAGNAC | 210157.688544 | 403717.366279 | 31 | 613875.054823 |
2.1 Import des données de l’Insee
En ce qui concerne nos informations communales, on va utiliser l’une des
sources de l’Insee les plus utilisées : les données Filosofi
.
Afin de faciliter la récupération de celles-ci, nous allons
utiliser le package communautaire pynsee
:
Note
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 l’Insee (insee.fr)
Dans ce chapitre, nous allons exclusivement utiliser cette deuxième
approche. Cela se fera par le module pynsee.download
.
La liste des données disponibles depuis ce package est ici.
La fonction download_file
attend un identifiant unique
pour savoir quelle base de données aller chercher et
restructurer depuis le
site insee.fr.
Connaître la liste des bases disponibles
Pour connaître la liste des bases disponibles, vous
pouvez utiliser la fonction meta = pynsee.get_file_list()
après avoir fait import pynsee
.
Celle-ci renvoie un DataFrame
dans lequel on peut
rechercher, par exemple grâce à une recherche
de mots-clefs :
= pynsee.get_file_list()
meta "label"].str.contains(r"Filosofi.*2016")] meta.loc[meta[
id | name | label | collection | link | type | zip | big_zip | data_file | tab | ... | label_col | date_ref | meta_file | separator | type_col | long_col | val_col | encoding | last_row | missing_value | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
79 | FILOSOFI_COM_2016 | FILOSOFI_COM | Données Filosofi niveau communal – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | COM | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
80 | FILOSOFI_EPCI_2016 | FILOSOFI_EPCI | Données Filosofi niveau EPCI – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | EPCI | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
81 | FILOSOFI_ARR_2016 | FILOSOFI_ARR | Données Filosofi niveau arondissement – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | ARR | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
82 | FILOSOFI_DEP_2016 | FILOSOFI_DEP | Données Filosofi niveau départemental – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | DEP | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
83 | FILOSOFI_REG_2016 | FILOSOFI_REG | Données Filosofi niveau régional – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | REG | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
84 | FILOSOFI_METRO_2016 | FILOSOFI_METRO | Données Filosofi niveau France métropolitaine ... | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | METRO | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
85 | FILOSOFI_AU2010_2016 | FILOSOFI_AU2010 | Données Filosofi niveau aire urbaine – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | AU2010 | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
86 | FILOSOFI_UU2010_2016 | FILOSOFI_UU2010 | Données Filosofi niveau unité urbaine – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | UU2010 | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
87 | FILOSOFI_ZE2010_2016 | FILOSOFI_ZE2010 | Données Filosofi niveau zone d’emploi – 2016 | FILOSOFI | https://www.insee.fr/fr/statistiques/fichier/4... | xls | True | False | base-cc-filosofi-2016.xls | ZE2010 | ... | NaN | 2016-01-01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
9 rows × 24 columns
Ici, meta['label'].str.contains(r"Filosofi.*2016")
signifie:
“pandas
trouve moi tous les labels où sont contenus les termes Filosofi et 2016.”
(.*
signifiant “peu m’importe le nombre de mots ou caractères entre”)
On va utiliser les données Filosofi (données de revenus) au niveau communal de 2016.
Ce n’est pas la même année que les données d’émission de CO2, ce n’est donc pas parfaitement rigoureux,
mais cela permettra tout de même d’illustrer
les principales fonctionnalités de Pandas
Le point d’entrée principal de la fonction pynsee
est la fonction download_file
.
Le code pour télécharger les données est le suivant :
from pynsee.download import download_file
= download_file("FILOSOFI_COM_2016") filosofi
Le DataFrame en question a l’aspect suivant :
CODGEO | LIBGEO | NBMENFISC16 | NBPERSMENFISC16 | MED16 | PIMP16 | TP6016 | TP60AGE116 | TP60AGE216 | TP60AGE316 | ... | PPEN16 | PPAT16 | PPSOC16 | PPFAM16 | PPMINI16 | PPLOGT16 | PIMPOT16 | D116 | D916 | RD16 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
7617 | 22362 | Tréguier | 1075 | 1958.5 | 18506 | 37 | 18 | NaN | NaN | NaN | ... | 47.1 | 9.2 | 7.8 | 1.7 | 3.7 | 2.4 | -14.2 | 10624 | 32887.666666666664 | 3.095601154618474 |
26925 | 68304 | Sentheim | 596 | 1477.5 | 23423.6 | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
30781 | 78688 | Voisins-le-Bretonneux | 4304 | 11784 | 33332.666666666664 | 83 | 5 | NaN | NaN | NaN | ... | 21.9 | 8.7 | 1.8 | 1.1 | 0.3 | 0.4 | -23.8 | 18540.357142857145 | 56755.6 | 3.0611923795581064 |
12220 | 32366 | Saint-Brès | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1377 | 03187 | Montoldre | 188 | 467 | 19624.8 | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows × 29 columns
Pandas
a géré automatiquement les types de variables. Il le fait relativement bien, mais une vérification est toujours utile pour les variables qui ont un statut spécifique.
Pour les variables qui ne sont pas en type float
alors qu’elles devraient l’être, on modifie leur type.
2:]] = filosofi.loc[:, filosofi.columns[2:]].apply(
filosofi.loc[:, filosofi.columns[="coerce"
pd.to_numeric, errors )
Un simple coup d’oeil sur les données
donne une idée assez précise de la manière dont les données sont organisées.
On remarque que certaines variables de filosofi
semblent avoir beaucoup de valeurs manquantes (secret statistique)
alors que d’autres semblent complètes.
Si on désire exploiter filosofi
, il faut faire attention à la variable choisie.
Notre objectif à terme va être de relier l’information contenue entre ces
deux jeux de données. En effet, sinon, nous risquons d’être frustré : nous allons
vouloir en savoir plus sur les émissions de gaz carbonique mais seront très
limités dans les possibilités d’analyse sans ajout d’une information annexe
issue de filosofi
.
3 Les indices
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.
Pour le moment, on va prendre comme acquis que les codes communes (dits aussi codes Insee) permettent d’identifier de manière unique une commune. Un exercice ultérieur permettra de s’en assurer.
Pandas
propose un système d’indice qui permet d’ordonner les variables mais également de gagner
en efficacité sur certains traitements, comme des recherches d’observations. Le prochain
exercice illustre cette fonctionnalité.
Exercice 3 : Les indices
On suppose ici qu’on peut se fier aux codes communes. En effet, on a un même ordre de grandeur de communes dans les deux bases.
print(emissions[["INSEE commune", "Commune"]].nunique())
print(filosofi[["CODGEO", "LIBGEO"]].nunique())
INSEE commune 35798
Commune 33338
dtype: int64
CODGEO 34932
LIBGEO 32676
dtype: int64
Fixer comme indice la variable de code commune dans les deux bases. Regarder le changement que cela induit sur le display du
DataFrame
Les deux premiers chiffres des codes communes sont le numéro de département. Créer une variable de département
dep
dansemissions
etfilosofi
Calculer les émissions totales par secteur pour chaque département. Mettre en log ces résultats dans un objet
emissions_log
. Garder 5 départements et produire unbarplot
grâce à la méthode plot (la figure n’a pas besoin d’être vraiment propre, c’est seulement pour illustrer cette méthode)Repartir de
emissions
. 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. Essayer de comprendre pourquoi ce sont ces départements qui apparaissent en tête du classement. Pour cela, il peut être utile de regarder les caractéristiques de ces départements dansfilosofi
En pratique, l’utilisation des indices en Pandas
peut être piégeuse, notamment lorsqu’on
associe des sources de données.
Il est plutôt recommandé de ne pas les utiliser ou de les utiliser avec parcimonie,
cela pourra éviter de mauvaises surprises.
4 Restructurer les données
Quand on a plusieurs informations pour un même individu ou groupe, on retrouve généralement deux types de structure de données :
- format wide : les données comportent des observations répétées, pour un même individu (ou groupe), dans des colonnes différentes
- format long : les données comportent des observations répétées, pour un même individu, dans des lignes différentes avec une colonne permettant de distinguer les niveaux d’observations
Un exemple de la distinction entre les deux peut être pris à l’ouvrage de référence d’Hadley Wickham, R for Data Science:
L’aide mémoire suivante aidera à se rappeler les fonctions à appliquer si besoin :
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.
Les formats wide sont plutôt pensés pour des tableurs comme Excel
ou on dispose d’un nombre réduit
de lignes à partir duquel faire des tableaux croisés dynamiques.
Le prochain exercice propose donc une telle restructuration de données. Les données de l’ADEME, et celles de l’Insee également, sont au format wide. Le prochain exercice illustre l’intérêt de faire la conversion long \(\to\) wide avant de faire un graphique.
Exercice 5: Restructurer les données : wide to long
Créer une copie des données de l’
ADEME
en faisantdf_wide = emissions_wide.copy()
Restructurer les données au format long pour avoir des données d’émissions par secteur en gardant comme niveau d’analyse la commune (attention aux autres variables identifiantes).
Faire la somme par secteur et représenter graphiquement
Garder, pour chaque département, le secteur le plus polluant
5 Combiner les données
5.1 Travail préliminaire
Jusqu’à présent lorsque nous avons produit des statistiques descriptives, celles-ci étaient univariées, c’est-à-dire que nous produisions de l’information sur une variable mais nous ne la mettions pas en lien avec une autre. Pourtant, on est rapidement amené à désirer expliquer certaines statistiques agrégées à partir de caractéristiques issues d’une autre source de données. Cela implique donc d’associer des jeux de données, autrement dit de mettre en lien deux jeux de données présentant le même niveau d’information.
On appelle ceci faire un merge ou un join. De manière illustrée, ceci revient à effectuer ce type d’opération :
Avant de faire ceci, il est néanmoins nécessaire de s’assurer que les variables communes entre les bases de données présentent le bon niveau d’information.
Exercice 6: vérification des clés de jointure
On commence par vérifier les dimensions des DataFrames
et la structure de certaines variables clés.
En l’occurrence, les variables fondamentales pour lier nos données sont les variables communales.
Ici, on a deux variables géographiques: un code commune et un nom de commune.
Vérifier les dimensions des DataFrames.
Identifier dans
filosofi
les noms de communes qui correspondent à plusieurs codes communes et sélectionner leurs codes. En d’autres termes, identifier lesLIBGEO
tels qu’il existe des doublons deCODGEO
et les stocker dans un vecteurx
(conseil: faire attention à l’index dex
).
On se focalise temporairement sur les observations où le libellé comporte plus de deux codes communes différents
Question 3. Regarder dans
filosofi
ces observations.Question 4. Pour mieux y voir, réordonner la base obtenue par order alphabétique.
Question 5. Déterminer la taille moyenne (variable nombre de personnes:
NBPERSMENFISC16
) et quelques statistiques descriptives de ces données. Comparer aux mêmes statistiques sur les données où libellés et codes communes coïncident.Question 6. Vérifier les grandes villes (plus de 100 000 personnes), la proportion de villes pour lesquelles un même nom est associé à différents codes commune.
Question 7. Vérifier dans
filosofi
les villes dont le libellé est égal à Montreuil. Vérifier également celles qui contiennent le terme ‘Saint-Denis’.
Ce petit exercice permet de se rassurer car les libellés dupliqués sont en fait des noms de commune identiques mais qui ne sont pas dans le même département. Il ne s’agit donc pas d’observations dupliquées. On peut donc se fier aux codes communes, qui eux sont uniques.
5.2 Associer des données
Une information que l’on cherche à obtenir s’obtient de moins en moins à partir d’une unique base de données. Il devient commun de devoir combiner des données issues de sources différentes.
Nous allons ici nous focaliser sur le cas le plus favorable qui est la situation où une information permet d’apparier de manière exacte deux bases de données (autrement nous 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 ou un identifiant de code commune, ce qui est notre cas.
Il est recommandé de lire ce guide assez complet sur la question des jointures avec R qui donne des recommandations également utiles en Python
.
Dans le langage courant du statisticien,
on utilise de manière indifférente les termes merge ou join. Le deuxième terme provient de la syntaxe SQL
.
Quand on fait du Pandas
, on utilise plutôt la commande merge.
Exercice 7: Calculer l'empreinte carbone par habitant
En premier lieu, on va calculer l’empreinte carbone de chaque commune.
Créer une variable
emissions
qui correspond aux émissions totales d’une communeFaire une jointure à gauche entre les données d’émissions et les données de cadrage2.
Calculer l’empreinte carbone (émissions totales / population).
A ce stade nous pourrions avoir envie d’aller vers la modélisation pour essayer d’expliquer les déterminants de l’empreinte carbone à partir de variables communales. Une approche inférentielle nécessite néanmoins pour être pertinente de vérifier en amont des statistiques descriptives.
- Sortir un histogramme en niveau puis en log de l’empreinte carbone communale.
Avec une meilleure compréhension de nos données, nous nous rapprochons de la statistique inférentielle. Néanmoins, nous avons jusqu’à présent construit des statistiques univariées mais n’avons pas cherché à comprendre les résultats en regardant le lien avec d’autres variables. Cela nous amène vers la statistique bivariée, notamment l’analyse des corrélations. Ce travail est important puisque toute modélisation ultérieure consistera à raffiner l’analyse des corrélations pour tenir compte des corrélations croisées entre multiples facteurs. On propose ici de faire cette analyse de manière minimale.
- Regarder la corrélation entre les variables de cadrage et l’empreinte carbone. Certaines variables semblent-elles pouvoir potentiellement influer sur l’empreinte carbone ?
A l’issue de la question 5, le graphique des corrélations est le suivant :
6 Formatter des tableaux de statistiques descriptives
De manière automatique un dataframe Pandas
est mis en forme lorsqu’il est visualisé depuis un notebook.
Cette mise en forme est pratique pour voir
les données, une tâche indispensable pour les data scientists
mais ne permet pas d’aller vraiment au-delà. Dans une phase
exploratoire, il peut être pratique d’avoir un tableau
un peu plus complet, intégrant notamment des visualisations
minimalistes, pour mieux connaître ses données. Dans la phase
finale d’un projet, lorsqu’on communique sur un projet, il
est avantageux de disposer d’une visualisation attrative.
Pour ces deux besoins, les sorties des notebooks sont
une réponse peu satisfaisante, en plus de nécessiter
le medium du notebook qui peut en rebuter certains.
Heureusement, le tout jeune package great_tables
permet, de manière programmatique
et assez simple, la création de tableaux
qui n’ont rien à envier à des productions manuelles faites dans Excel
et difficilement répliquables. great_tables
construit des tableaux
html ce qui offre une grande richesse dans la mise en forme.
L’exercice suivant proposera de construire un tableau avec
ce package, pas à pas.
Afin de se concentrer sur la construction du tableau, les préparations de données à faire en amont sont données directement. Nous allons repartir de ce jeu de données:
3) emissions_merged.head(
INSEE commune | Commune | Agriculture | Autres transports | Autres transports international | CO2 biomasse hors-total | Déchets | Energie | Industrie hors-énergie | Résidentiel | ... | PPSOC16 | PPFAM16 | PPMINI16 | PPLOGT16 | PIMPOT16 | D116 | D916 | RD16 | dep_y | empreinte | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 01001 | L'ABERGEMENT-CLEMENCIAT | 3711.425991 | NaN | NaN | 432.751835 | 101.430476 | 2.354558 | 6.911213 | 309.358195 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 01 | 7.196009 |
1 | 01002 | L'ABERGEMENT-DE-VAREY | 475.330205 | NaN | NaN | 140.741660 | 140.675439 | 2.354558 | 6.911213 | 104.866444 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 01 | 5.374240 |
2 | 01004 | AMBERIEU-EN-BUGEY | 499.043526 | 212.577908 | NaN | 10313.446515 | 5314.314445 | 998.332482 | 2930.354461 | 16616.822534 | ... | 6.9 | 2.8 | 2.1 | 2.0 | -15.7 | 10457.083333 | 33880.555556 | 3.239962 | 01 | 4.446141 |
3 rows × 45 columns
Nous allons construire un tableau de statistiques descriptives par département mettant en parallèle l’empreinte carbone, le revenu médian et la population de chaque département
= (
emissions_table
emissions_merged.rename(={"dep_y": "dep", "NBPERSMENFISC16": "population", "MED16": "revenu"}
columns
)"dep")
.groupby(
.agg("empreinte": "sum", "revenu": "median", "population": "sum"}
{# pas vraiment le revenu médian
)
.reset_index()="empreinte")
.sort_values(by )
Dans ce tableau nous allons intégrer des barres horizontales, à la manière des exemples présentés ici. Cela se fait en incluant directement le code html dans la colonne du DataFrame
def create_bar(
float, max_width: int, height: int, color: str = "green"
prop_fill: -> str:
) """Create divs to represent prop_fill as a bar."""
= round(max_width * prop_fill, 2)
width = f"{width}px"
px_width return f"""\
<div style="width: {max_width}px; background-color: lightgrey;">\
<div style="height:{height}px;width:{px_width};background-color:{color};"></div>\
</div>\
"""
= {"empreinte": "green", "revenu": "red", "population": "blue"}
colors
for variable in ["empreinte", "revenu", "population"]:
f"raw_perc_{variable}"] = (
emissions_table[/ emissions_table[variable].max()
emissions_table[variable]
)f"bar_{variable}"] = emissions_table[f"raw_perc_{variable}"].map(
emissions_table[lambda x: create_bar(x, max_width=75, height=20, color=colors[variable])
)
Nous ne gardons que les 5 plus petites empreintes carbone, et les cinq plus importantes.
= (
emissions_min 5)
emissions_table.head(="5 départements les moins pollueurs")
.assign(grp=True)
.reset_index(drop
)= (
emissions_max 5)
emissions_table.tail(="5 départements les plus pollueurs")
.assign(grp=True)
.reset_index(drop
)
= pd.concat([emissions_min, emissions_max]) emissions_table
Enfin, pour pouvoir utiliser quelques fonctions
pratiques pour sélectionner des colonnes à partir
de motifs, nous allons convertir les données
au format Polars
import polars as pl
= pl.from_pandas(emissions_table) emissions_table
Exercice 8: Un beau tableau de statistiques descriptives (exercice libre)
En prenant comme base ce tableau
="grp", rowname_col="dep") GT(emissions_table, groupname_col
construire un tableau dans le style de celui ci-dessous
Le tableau à obtenir:
Empreinte carbone | |||||||||
---|---|---|---|---|---|---|---|---|---|
Premières statistiques descriptives à affiner | |||||||||
Empreinte | Revenu médian | Population | |||||||
Empreinte carbone | (%)* | Revenu | (%)* | Population | (%)* | ||||
5 départements les moins pollueurs | |||||||||
75 | 8.12 | 0.4% | |
30.5K | 100.0% | |
2.07M | 82.9% | |
92 | 14.72 | 0.8% | |
28.6K | 93.6% | |
1.58M | 63.3% | |
93 | 16.79 | 0.9% | |
17.3K | 56.6% | |
1.59M | 63.4% | |
94 | 20.72 | 1.1% | |
22.4K | 73.5% | |
1.35M | 53.8% | |
83 | 82.37 | 4.3% | |
20.8K | 68.3% | |
1.05M | 42.0% | |
5 départements les plus pollueurs | |||||||||
62 | 962.41 | 50.5% | |
19.7K | 64.5% | |
1.44M | 57.5% | |
76 | 966.25 | 50.7% | |
21.0K | 69.0% | |
1.21M | 48.3% | |
80 | 969.32 | 50.9% | |
20.0K | 65.7% | |
535.82K | 21.4% | |
51 | 983.67 | 51.6% | |
22.6K | 74.1% | |
531.40K | 21.2% | |
77 | 1,906.19 | 100.0% | |
23.8K | 77.9% | |
1.37M | 54.9% | |
*Note: Le revenu médian présenté ici est une approximation du revenu médian du département. | |||||||||
Lecture: Les colonnes (%) présentées ci-dessus sont rapportées à la valeur maximale de la variable | |||||||||
Source: Calculs à partir des données de l'Ademe |
Grâce à celui-ci, on peut déjà comprendre que notre définition de l’empreinte carbone est certainement défaillante. Il apparaît peu plausible que les habitants du 77 aient une empreinte 500 fois supérieure à celle de Paris intra-muros. La raison principale ? On n’est pas sur un concept d’émissions à la consommation mais à la production, ce qui pénalise les espaces industriels ou les espaces avec des aéroports…
Pour aller plus loin sur la construction de tableaux
avec great_tables
, vous pouvez répliquer
cet exercice
de production de tableaux électoraux
que j’ai proposé pour un cours de R
avec gt
, l’équivalent
de great_tables
pour R
.
7 Exercices bonus
Les plus rapides d’entre vous sont invités à aller un peu plus loin en s’entraînant avec des exercices bonus qui proviennent du site de Xavier Dupré. 3 notebooks en lien avec numpy
et pandas
vous y sont proposés :
- Calcul Matriciel, Optimisation : énoncé / corrigé
- DataFrame et Graphes : énoncé / corrigé
- Pandas et itérateurs : énoncé / corrigé
Informations additionnelles
environment files have been tested on.
Latest built version: 2024-04-27
Python version used:
'3.11.6 | packaged by conda-forge | (main, Oct 3 2023, 10:40:35) [GCC 12.3.0]'
Package | Version |
---|---|
affine | 2.4.0 |
aiobotocore | 2.12.2 |
aiohttp | 3.9.3 |
aioitertools | 0.11.0 |
aiosignal | 1.3.1 |
alembic | 1.13.1 |
aniso8601 | 9.0.1 |
annotated-types | 0.6.0 |
appdirs | 1.4.4 |
archspec | 0.2.3 |
astroid | 3.1.0 |
asttokens | 2.4.1 |
attrs | 23.2.0 |
Babel | 2.14.0 |
bcrypt | 4.1.2 |
beautifulsoup4 | 4.12.3 |
black | 24.4.2 |
blinker | 1.7.0 |
blis | 0.7.11 |
bokeh | 3.4.0 |
boltons | 23.1.1 |
boto3 | 1.34.51 |
botocore | 1.34.51 |
branca | 0.7.1 |
Brotli | 1.1.0 |
cachetools | 5.3.3 |
cartiflette | 0.0.2 |
Cartopy | 0.23.0 |
catalogue | 2.0.10 |
cattrs | 23.2.3 |
certifi | 2024.2.2 |
cffi | 1.16.0 |
charset-normalizer | 3.3.2 |
click | 8.1.7 |
click-plugins | 1.1.1 |
cligj | 0.7.2 |
cloudpathlib | 0.16.0 |
cloudpickle | 3.0.0 |
colorama | 0.4.6 |
comm | 0.2.2 |
commonmark | 0.9.1 |
conda | 24.3.0 |
conda-libmamba-solver | 24.1.0 |
conda-package-handling | 2.2.0 |
conda_package_streaming | 0.9.0 |
confection | 0.1.4 |
contextily | 1.6.0 |
contourpy | 1.2.1 |
cryptography | 42.0.5 |
cycler | 0.12.1 |
cymem | 2.0.8 |
cytoolz | 0.12.3 |
dask | 2024.4.1 |
dask-expr | 1.0.10 |
debugpy | 1.8.1 |
decorator | 5.1.1 |
dill | 0.3.8 |
distributed | 2024.4.1 |
distro | 1.9.0 |
docker | 7.0.0 |
duckdb | 0.10.1 |
en-core-web-sm | 3.7.1 |
entrypoints | 0.4 |
et-xmlfile | 1.1.0 |
exceptiongroup | 1.2.0 |
executing | 2.0.1 |
fastjsonschema | 2.19.1 |
fiona | 1.9.6 |
flake8 | 7.0.0 |
Flask | 3.0.2 |
folium | 0.16.0 |
fontawesomefree | 6.5.1 |
fonttools | 4.51.0 |
frozenlist | 1.4.1 |
fsspec | 2023.12.2 |
GDAL | 3.8.4 |
gensim | 4.3.2 |
geographiclib | 2.0 |
geopandas | 0.12.2 |
geoplot | 0.5.1 |
geopy | 2.4.1 |
gitdb | 4.0.11 |
GitPython | 3.1.43 |
google-auth | 2.29.0 |
graphene | 3.3 |
graphql-core | 3.2.3 |
graphql-relay | 3.2.0 |
graphviz | 0.20.3 |
great-tables | 0.5.0 |
greenlet | 3.0.3 |
gunicorn | 21.2.0 |
htmltools | 0.5.1 |
hvac | 2.1.0 |
idna | 3.6 |
imageio | 2.34.1 |
importlib_metadata | 7.1.0 |
importlib_resources | 6.4.0 |
inflate64 | 1.0.0 |
ipykernel | 6.29.3 |
ipython | 8.22.2 |
ipywidgets | 8.1.2 |
isort | 5.13.2 |
itsdangerous | 2.1.2 |
jedi | 0.19.1 |
Jinja2 | 3.1.3 |
jmespath | 1.0.1 |
joblib | 1.3.2 |
jsonpatch | 1.33 |
jsonpointer | 2.4 |
jsonschema | 4.21.1 |
jsonschema-specifications | 2023.12.1 |
jupyter-cache | 1.0.0 |
jupyter_client | 8.6.1 |
jupyter_core | 5.7.2 |
jupyterlab_widgets | 3.0.10 |
kaleido | 0.2.1 |
kiwisolver | 1.4.5 |
kubernetes | 29.0.0 |
langcodes | 3.4.0 |
language_data | 1.2.0 |
lazy_loader | 0.4 |
libmambapy | 1.5.7 |
llvmlite | 0.42.0 |
locket | 1.0.0 |
lxml | 5.2.1 |
lz4 | 4.3.3 |
Mako | 1.3.2 |
mamba | 1.5.7 |
mapclassify | 2.6.1 |
marisa-trie | 1.1.0 |
Markdown | 3.6 |
MarkupSafe | 2.1.5 |
matplotlib | 3.8.3 |
matplotlib-inline | 0.1.6 |
mccabe | 0.7.0 |
menuinst | 2.0.2 |
mercantile | 1.2.1 |
mizani | 0.11.2 |
mlflow | 2.11.3 |
mlflow-skinny | 2.11.3 |
msgpack | 1.0.7 |
multidict | 6.0.5 |
multivolumefile | 0.2.3 |
munkres | 1.1.4 |
murmurhash | 1.0.10 |
mypy | 1.9.0 |
mypy-extensions | 1.0.0 |
nbclient | 0.10.0 |
nbformat | 5.10.4 |
nest_asyncio | 1.6.0 |
networkx | 3.3 |
nltk | 3.8.1 |
numba | 0.59.1 |
numpy | 1.26.4 |
oauthlib | 3.2.2 |
opencv-python-headless | 4.9.0.80 |
openpyxl | 3.1.2 |
OWSLib | 0.28.1 |
packaging | 23.2 |
pandas | 2.2.1 |
paramiko | 3.4.0 |
parso | 0.8.4 |
partd | 1.4.1 |
pathspec | 0.12.1 |
patsy | 0.5.6 |
Pebble | 5.0.7 |
pexpect | 4.9.0 |
pickleshare | 0.7.5 |
pillow | 10.3.0 |
pip | 24.0 |
pkgutil_resolve_name | 1.3.10 |
platformdirs | 4.2.0 |
plotly | 5.19.0 |
plotnine | 0.13.5 |
pluggy | 1.4.0 |
polars | 0.20.18 |
preshed | 3.0.9 |
prometheus_client | 0.20.0 |
prometheus-flask-exporter | 0.23.0 |
prompt-toolkit | 3.0.42 |
protobuf | 4.25.3 |
psutil | 5.9.8 |
ptyprocess | 0.7.0 |
pure-eval | 0.2.2 |
py7zr | 0.20.8 |
pyarrow | 15.0.0 |
pyarrow-hotfix | 0.6 |
pyasn1 | 0.5.1 |
pyasn1-modules | 0.3.0 |
pybcj | 1.0.2 |
pycodestyle | 2.11.1 |
pycosat | 0.6.6 |
pycparser | 2.21 |
pycryptodomex | 3.20.0 |
pydantic | 2.7.1 |
pydantic_core | 2.18.2 |
pyflakes | 3.2.0 |
Pygments | 2.17.2 |
PyJWT | 2.8.0 |
pylint | 3.1.0 |
PyNaCl | 1.5.0 |
pynsee | 0.1.7 |
pyOpenSSL | 24.0.0 |
pyparsing | 3.1.2 |
pyppmd | 1.1.0 |
pyproj | 3.6.1 |
pyshp | 2.3.1 |
PySocks | 1.7.1 |
python-dateutil | 2.9.0 |
python-dotenv | 1.0.1 |
python-magic | 0.4.27 |
pytz | 2024.1 |
pyu2f | 0.1.5 |
pywaffle | 1.1.0 |
PyYAML | 6.0.1 |
pyzmq | 25.1.2 |
pyzstd | 0.15.10 |
QtPy | 2.4.1 |
querystring-parser | 1.2.4 |
rasterio | 1.3.10 |
referencing | 0.34.0 |
regex | 2023.12.25 |
requests | 2.31.0 |
requests-cache | 1.2.0 |
requests-oauthlib | 2.0.0 |
rpds-py | 0.18.0 |
rsa | 4.9 |
Rtree | 1.2.0 |
ruamel.yaml | 0.18.6 |
ruamel.yaml.clib | 0.2.8 |
s3fs | 2023.12.2 |
s3transfer | 0.10.1 |
scikit-image | 0.23.2 |
scikit-learn | 1.4.1.post1 |
scipy | 1.13.0 |
seaborn | 0.13.2 |
setuptools | 69.2.0 |
shapely | 2.0.3 |
six | 1.16.0 |
smart-open | 6.4.0 |
smmap | 5.0.0 |
snuggs | 1.4.7 |
sortedcontainers | 2.4.0 |
soupsieve | 2.5 |
spacy | 3.7.4 |
spacy-legacy | 3.0.12 |
spacy-loggers | 1.0.5 |
SQLAlchemy | 2.0.29 |
sqlparse | 0.4.4 |
srsly | 2.4.8 |
stack-data | 0.6.2 |
statsmodels | 0.14.1 |
tabulate | 0.9.0 |
tblib | 3.0.0 |
tenacity | 8.2.3 |
texttable | 1.7.0 |
thinc | 8.2.3 |
threadpoolctl | 3.4.0 |
tifffile | 2024.4.24 |
tomli | 2.0.1 |
tomlkit | 0.12.4 |
toolz | 0.12.1 |
topojson | 1.8 |
tornado | 6.4 |
tqdm | 4.66.2 |
traitlets | 5.14.2 |
truststore | 0.8.0 |
typer | 0.9.4 |
typing_extensions | 4.11.0 |
tzdata | 2024.1 |
Unidecode | 1.3.8 |
url-normalize | 1.4.3 |
urllib3 | 1.26.18 |
wasabi | 1.1.2 |
wcwidth | 0.2.13 |
weasel | 0.3.4 |
webcolors | 1.13 |
webdriver-manager | 4.0.1 |
websocket-client | 1.7.0 |
Werkzeug | 3.0.2 |
wheel | 0.43.0 |
widgetsnbextension | 4.0.10 |
wordcloud | 1.9.3 |
wrapt | 1.16.0 |
xgboost | 2.0.3 |
xlrd | 2.0.1 |
xyzservices | 2024.4.0 |
yarl | 1.9.4 |
yellowbrick | 1.5 |
zict | 3.0.0 |
zipp | 3.17.0 |
zstandard | 0.22.0 |
View file history
SHA | Date | Author | Description |
---|---|---|---|
4d678bf | 2024-04-23 12:09:46 | linogaliana | Typo |
d75641d | 2024-04-22 18:59:01 | Lino Galiana | Editorialisation des chapitres de manipulation de données (#491) |
7298c6c | 2024-04-19 21:34:00 | Lino Galiana | Exercice great_tables (#489) |
c03aa61 | 2024-01-16 17:33:18 | Lino Galiana | Exercice sur les chemins relatifs (#483) |
005d89b | 2023-12-20 17:23:04 | Lino Galiana | Finalise l’affichage des statistiques Git (#478) |
3fba612 | 2023-12-17 18:16:42 | Lino Galiana | Remove some badges from python (#476) |
1684220 | 2023-12-02 12:06:40 | Antoine Palazzolo | Première partie de relecture de fin du cours (#467) |
1f23de2 | 2023-12-01 17:25:36 | Lino Galiana | Stockage des images sur S3 (#466) |
a06a268 | 2023-11-23 18:23:28 | Antoine Palazzolo | 2ème relectures chapitres ML (#457) |
889a71b | 2023-11-10 11:40:51 | Antoine Palazzolo | Modification TP 3 (#443) |
8071bbb | 2023-10-23 17:43:37 | tomseimandi | Make minor changes to 02b, 03, 04a (#440) |
df01f01 | 2023-10-10 15:55:04 | Lino Galiana | Menus automatisés (#432) |
7221e7b | 2023-10-10 14:00:44 | Thomas Faria | Relecture Thomas TD Pandas (#431) |
98bb886 | 2023-10-09 11:50:03 | Lino Galiana | typo |
a771183 | 2023-10-09 11:27:45 | Antoine Palazzolo | Relecture TD2 par Antoine (#418) |
ac80862 | 2023-10-07 21:05:25 | Lino Galiana | Relecture antuki (#427) |
5ab34aa | 2023-10-04 14:54:20 | Kim A | Relecture Kim pandas & git (#416) |
7e03cea | 2023-10-04 14:07:17 | Lino Galiana | Clean pandas tutorial and exercises (#417) |
154f09e | 2023-09-26 14:59:11 | Antoine Palazzolo | Des typos corrigées par Antoine (#411) |
9a4e226 | 2023-08-28 17:11:52 | Lino Galiana | Action to check URL still exist (#399) |
9977c5d | 2023-08-28 10:43:36 | Lino Galiana | Fix bug path pandas (#397) |
a8f90c2 | 2023-08-28 09:26:12 | Lino Galiana | Update featured paths (#396) |
3bdf3b0 | 2023-08-25 11:23:02 | Lino Galiana | Simplification de la structure 🤓 (#393) |
5d4874a | 2023-08-11 15:09:33 | Lino Galiana | Pimp les introductions des trois premières parties (#387) |
130ed71 | 2023-07-18 19:37:11 | Lino Galiana | Restructure les titres (#374) |
ef28fef | 2023-07-07 08:14:42 | Lino Galiana | Listing pour la première partie (#369) |
f21a24d | 2023-07-02 10:58:15 | Lino Galiana | Pipeline Quarto & Pages 🚀 (#365) |
3c880d5 | 2022-12-27 17:34:59 | Lino Galiana | Chapitre regex + Change les boites dans plusieurs chapitres (#339) |
89d0798 | 2022-11-02 10:19:58 | Lino Galiana | Ajoute icone aux autres TP (#317) |
a3eadd4 | 2022-11-01 18:51:14 | Romain Avouac | Modèle de notebooks de correction exécutables (#304) |
af763cc | 2022-10-12 10:17:56 | Lino Galiana | Reprise exercice geopandas (#294) |
1ef97df | 2022-10-11 12:14:03 | Lino Galiana | Relecture chapitre geopandas (#289) |
e2b53ac | 2022-09-28 17:09:31 | Lino Galiana | Retouche les chapitres pandas (#287) |
eb8f922 | 2022-09-22 17:40:43 | Lino Galiana | Corrige bug TP pandas (#276) |
f10815b | 2022-08-25 16:00:03 | Lino Galiana | Notebooks should now look more beautiful (#260) |
494a85a | 2022-08-05 14:49:56 | Lino Galiana | Images featured ✨ (#252) |
d201e3c | 2022-08-03 15:50:34 | Lino Galiana | Pimp la homepage ✨ (#249) |
12965ba | 2022-05-25 15:53:27 | Lino Galiana | :launch: Bascule vers quarto (#226) |
9c71d6e | 2022-03-08 10:34:26 | Lino Galiana | Plus d’éléments sur S3 (#218) |
6777f03 | 2021-10-29 09:38:09 | Lino Galiana | Notebooks corrections (#171) |
2a8809f | 2021-10-27 12:05:34 | Lino Galiana | Simplification des hooks pour gagner en flexibilité et clarté (#166) |
b138cf3 | 2021-10-21 18:05:59 | Lino Galiana | Mise à jour TP webscraping et API (#164) |
4870662 | 2021-10-05 08:29:33 | Romain Avouac | fix and simplify pyinsee install (#157) |
0677932 | 2021-10-03 15:32:51 | Lino Galiana | Ajoute un code pour download pynsee (#156) |
2fa78c9 | 2021-09-27 11:24:19 | Lino Galiana | Relecture de la partie numpy/pandas (#152) |
85ba119 | 2021-09-16 11:27:56 | Lino Galiana | Relectures des TP KA avant 1er cours (#142) |
2e4d586 | 2021-09-02 12:03:39 | Lino Galiana | Simplify badges generation (#130) |
bf5ebc5 | 2021-09-01 14:41:17 | Lino Galiana | Fix problem import pynsee (#128) |
4a317e3 | 2021-08-31 12:38:17 | Lino Galiana | pynsee pour importer des données Insee 🚀 (#127) |
4cdb759 | 2021-05-12 10:37:23 | Lino Galiana | :sparkles: :star2: Nouveau thème hugo :snake: :fire: (#105) |
7f9f97b | 2021-04-30 21:44:04 | Lino Galiana | 🐳 + 🐍 New workflow (docker 🐳) and new dataset for modelization (2020 🇺🇸 elections) (#99) |
6d010fa | 2020-09-29 18:45:34 | Lino Galiana | Simplifie l’arborescence du site, partie 1 (#57) |
66f9f87 | 2020-09-24 19:23:04 | Lino Galiana | Introduction des figures générées par python dans le site (#52) |
4677769 | 2020-09-15 18:19:24 | Lino Galiana | Nettoyage des coquilles pour premiers TP (#37) |
5c1e76d | 2020-09-09 11:25:38 | Lino Galiana | Ajout des éléments webscraping, regex, API (#21) |
d48e68f | 2020-09-08 18:35:07 | Lino Galiana | Continuer la partie pandas (#13) |
Footnotes
Par manque d’imagination, on est souvent tenté d’appeler notre dataframe principal
df
oudata
. C’est souvent une mauvaise idée puisque ce nom n’est pas très informatif quand on relit le code quelques semaines plus tard. L’autodocumentation, approche qui consiste à avoir un code qui se comprend de lui-même, est une bonne pratique et il est donc recommandé de donner un nom simple mais efficace pour connaître la nature du dataset en question.↩︎Idéalement, il serait nécessaire de s’assurer que cette jointure n’introduit pas de biais. En effet, comme nos années de référence ne sont pas forcément identiques, il peut y avoir un mismatch entre nos deux sources. Le TP étant déjà long, nous n’allons pas dans cette voie. Les lecteurs intéressés pourront effectuer une telle analyse en exercice supplémentaire.↩︎
Citation
BibTeX citation:
@book{galiana2023,
author = {Galiana, Lino},
title = {Python Pour La Data Science},
date = {2023},
url = {https://pythonds.linogaliana.fr/},
doi = {10.5281/zenodo.8229676},
langid = {en}
}
For attribution, please cite this work as:
Galiana, Lino. 2023. Python Pour La Data Science. https://doi.org/10.5281/zenodo.8229676.