2.6.1. Tutoriel 6: Données tabulaires avec Pandas
#
Dans cette section, nous aborderons les points suivants:
Pandas
2.6.1.1. Introduction#
[Pandas] (http://pandas.pydata.org/) est une bibliothèque open source qui fournit des structures de données et des outils d’analyse de données performants et faciles à utiliser. Pandas est particulièrement adapté à l’analyse des données tabulaires, c’est-à-dire des données qui peuvent être intégrées dans un tableau. En d’autres termes, si vous pouvez imaginer les données dans une feuille de calcul Excel, Pandas est l’outil qu’il vous faut.
Une [analyse récente de 2017] (https://stackoverflow.blog/2017/09/06/incredible-growth-python/) des questions de Stack Overflow a montré que python était le langage de programmation à la croissance la plus rapide et le plus utilisé dans le monde (dans les pays développés). En 2021, la croissance s’est stabilisée, mais Python reste en tête.

Lien pour générer votre propre version de cette figure
Une analyse de suivi a montré que cette croissance est due aux progiciels de science des données tels que numpy
, matplotlib
, et surtout pandas
.
La croissance exponentielle des pandas est due au fait qu’ils fonctionnent tout simplement. Il vous fait gagner du temps et vous aide à faire de la science de manière plus efficace.
Capacités de Pandas (extrait du [site Web de Pandas] (https://pandas.pydata.org/)) :
Un objet DataFrame rapide et efficace pour la manipulation des données avec indexation intégrée ;
Des outils pour lire et écrire des données entre des structures de données en mémoire et différents formats : CSV et fichiers texte, Microsoft Excel, bases de données SQL et le format rapide HDF5 ;
Alignement intelligent des données et traitement intégré des données manquantes : obtenez un alignement automatique basé sur les étiquettes dans les calculs et manipulez facilement des données désordonnées sous une forme ordonnée ;
Remodelage et pivotement flexibles des ensembles de données ;
Le découpage intelligent basé sur les étiquettes, l’indexation fantaisiste et le sous-ensemble de grands ensembles de données ;
Les colonnes peuvent être insérées et supprimées des structures de données pour une mutabilité de la taille ;
Agrégation ou transformation des données grâce à un puissant moteur de regroupement permettant des opérations de fractionnement, d’application et de combinaison sur les ensembles de données ;
Fusion et jonction d’ensembles de données à haute performance ;
L’indexation hiérarchique des axes offre un moyen intuitif de travailler avec des données de haute dimension dans une structure de données de dimension inférieure ;
Fonctionnalité des séries temporelles : génération de plages de dates et conversion de fréquence, statistiques à fenêtre mobile, régressions linéaires à fenêtre mobile, décalage de date et retard. Il est même possible de créer des décalages temporels spécifiques à un domaine et de joindre des séries temporelles sans perdre de données ;
Une optimisation poussée des performances, avec des chemins de code critiques écrits en Cython ou en C.
Dans ce notebook, nous allons passer en revue les capacités de base de Pandas. Il s’agit d’une bibliothèque très profonde, et vous devrez vous plonger dans la [documentation] (http://pandas.pydata.org/pandas-docs/stable/) pour une utilisation plus avancée.
Pandas a été créé par Wes McKinney. La plupart des exemples présentés ici sont tirés du livre de Wes McKinney Python for Data Analysis, qui comprend “un repo GitHub d’échantillons de code.
2.6.2. Pandas Data Structures : Série#
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 1
----> 1 import pandas as pd
2 import numpy as np
3 from matplotlib import pyplot as plt
ModuleNotFoundError: No module named 'pandas'
Une Series
représente un tableau de données à une dimension. La principale différence entre une Série
et un tableau numpy
est qu’une Série
possède un index. L’index contient les étiquettes que nous utilisons pour accéder aux données.
Il y a de nombreuses façons de créer une Série
. Nous n’en montrerons que quelques-unes.
(Les données proviennent de la NASA [Planetary Fact Sheet] (https://nssdc.gsfc.nasa.gov/planetary/factsheet/).)
nom = ['Mercure', 'Vénus', 'Terre']
valeurs = [0.3e24, 4.87e24, 5.97e24]
poids = pd.Series(valeurs, index=nom)
poids
# Les séries ont des méthodes de traçage intégrées.
poids.plot(kind='bar')
# Les opérations arithmétiques et la plupart des fonctions `numpy` peuvent être appliquées aux Series.
# Un point important est que les séries conservent leur index pendant ces opérations.
np.log(poids) / poids**2
# Nous pouvons accéder à l'objet index sous-jacent si nécessaire :
poids.index
2.6.2.1. Indexation#
# Nous pouvons récupérer les valeurs en utilisant l'index via l'attribut `.loc`.
poids.loc['Terre']
# Ou par position brute en utilisant `.iloc`
poids.iloc[2]
# Nous pouvons passer une liste ou un tableau à loc pour obtenir plusieurs lignes en retour :
poids.loc[['Vénus', 'Terre']]
# Et nous pouvons même utiliser la notation par tranches
poids.loc['Mercure':'Terre']
poids.iloc[:2]
# Si nécessaire, nous pouvons toujours récupérer les données brutes.
poids.values # un tableau numpy
poids.index # un objet Index pandas
2.6.2.2. Pandas Data Structures : DataFrame#
Il y a bien d’autres choses à faire avec les Series, mais elles sont limitées à une seule “colonne”. Une structure de données Pandas plus utile est le DataFrame. Un DataFrame est en fait un ensemble de séries qui partagent le même index. C’est un peu comme un tableau dans une feuille de calcul.
Ci-dessous, nous créons un DataFrame.
# nous créons d'abord un dictionnaire
data = {'poid' : [0.3e24, 4.87e24, 5.97e24], # kg
'diametre' : [4879e3, 12_104e3, 12_756e3], # m
'rotation_period' : [1407.6, np.nan, 23.9] # h
}
df = pd.DataFrame(data, index=['Mercure', 'Vénus', 'Terre'])
df
poid | diametre | rotation_period | |
---|---|---|---|
Mercure | 3.000000e+23 | 4879000.0 | 1407.6 |
Vénus | 4.870000e+24 | 12104000.0 | NaN |
Terre | 5.970000e+24 | 12756000.0 | 23.9 |
Pandas gère les données manquantes de manière très élégante, en conservant leur trace dans tous les calculs.
df.info()
Un large éventail de fonctions statistiques est disponible pour les Series
et les DataFrames
.
print(df.min())
print(df.mean())
print(df.std())
print(df.describe())
# Nous pouvons obtenir une seule colonne en tant que `Série` en utilisant la syntaxe python `getitem` sur l'objet `DataFrame`.
print(df['poid'])
# ...ou en utilisant la syntaxe des attributs.
print(df.poid)
# L'indexation fonctionne de la même manière que pour les séries
print(df.loc['Terre'])
print(df.iloc[2])
# Mais nous pouvons également spécifier la colonne à laquelle nous voulons accéder
df.loc['Terre', 'poid']
df.iloc[0:2, 0]
Si nous effectuons un calcul en utilisant les colonnes du DataFrame
, il conservera le même index :
volume = 4/3 * np.pi * (df.diametre/2)**3
df.poid / volume
Mercure 4933.216530
Vénus 5244.977070
Terre 5493.285577
dtype: float64
Que nous pouvons facilement ajouter en tant que colonne supplémentaire au DataFrame
:
df['densite'] = df.poid / volume
df
poid | diametre | rotation_period | densite | |
---|---|---|---|---|
Mercure | 3.000000e+23 | 4879000.0 | 1407.6 | 4933.216530 |
Vénus | 4.870000e+24 | 12104000.0 | NaN | 5244.977070 |
Terre | 5.970000e+24 | 12756000.0 | 23.9 | 5493.285577 |
2.6.2.3. Fusionner des données#
Pandas prend en charge un large éventail de méthodes pour fusionner différents ensembles de données. Ces méthodes sont décrites en détail dans la [documentation] (https://pandas.pydata.org/pandas-docs/stable/merging.html). Nous ne donnons ici que quelques exemples.
temperature = pd.Series([167, 464, 15, -65],
index=['Mercure', 'Vénus', 'Terre', 'Mars'],
name='temperature')
temperature
# renvoie un nouveau DataFrame
df.join(temperature)
# renvoie un nouveau DataFrame
df.join(temperature, how='right')
# renvoie un nouveau DataFrame
chacun = df.reindex(['Mercure', 'Vénus', 'Earth', 'Mars'])
chacun
Nous pouvons également indexer à l’aide d’une série booléenne. Ceci est très utile :
adultes = df[df.poid > 4e24]
adultes
poid | diametre | rotation_period | densite | |
---|---|---|---|---|
Vénus | 4.870000e+24 | 12104000.0 | NaN | 5244.977070 |
Terre | 5.970000e+24 | 12756000.0 | 23.9 | 5493.285577 |
df['is_big'] = df.poid > 4e24
df
2.6.2.4. Modifier des valeurs#
Nous voulons souvent modifier les valeurs d’un dataframe en fonction d’une règle. Pour modifier des valeurs, nous devons utiliser .loc
ou .iloc
df.loc['Terre', 'poid'] = 5.98+24
df.loc['Vénus', 'diametre'] += 1
df
poid | diametre | rotation_period | densite | |
---|---|---|---|---|
Mercure | 3.000000e+23 | 4879000.0 | 1407.6 | 4933.216530 |
Vénus | 4.870000e+24 | 12104001.0 | NaN | 5244.977070 |
Terre | 2.998000e+01 | 12756000.0 | 23.9 | 5493.285577 |
2.6.2.5. Tracé#
Les DataFrames intègrent toutes sortes de [tracés utiles] (https://pandas.pydata.org/pandas-docs/stable/visualization.html).
df.plot(kind='scatter', x='mass', y='diameter', grid=True)
df.plot(kind='bar')
2.6.2.6. Indices temporels#
Les index sont très puissants. Ils sont une grande partie de la raison pour laquelle Pandas
est si utile. Il existe différents index pour différents types de données. Les index temporels sont particulièrement intéressants !
two_years = pd.date_range(start='2014-01-01', end='2016-01-01', freq='D')
timeseries = pd.Series(np.sin(2 *np.pi *two_years.dayofyear / 365),
index=two_years)
timeseries.plot()
Nous pouvons utiliser la notation de découpage de Python à l’intérieur de .loc
pour sélectionner une plage de dates.
timeseries.loc['2015-01-01':'2015-07-01'].plot()
timeseries.index.month
timeseries.index.day
2.6.2.7. Lecture des fichiers de données : Données des stations météorologiques#
Dans cet exemple, nous utiliserons les données des stations météorologiques de la NOAA à partir de https://www.ncei.noaa.gov/products/land-based-station.
Les détails des fichiers que nous allons lire sont décrits dans ce fichier README.
import pooch
POOCH = pooch.create(
path=pooch.os_cache("noaa-data"),
base_url="doi:10.5281/zenodo.5564850/",
registry={
"data.txt": "md5:5129dcfd19300eb8d4d8d1673fcfbcb4",
},
)
datafile = POOCH.fetch("data.txt")
datafile
! head '/root/.cache/noaa-data/data.txt' # Remplacer cette valeur par le chemin de téléchargement indiqué ci-dessus
Nous avons maintenant un fichier texte sur notre disque dur appelé data.txt
.
Pour le lire dans pandas
, nous allons utiliser la fonction read_csv
. Cette fonction est incroyablement complexe et puissante. Vous pouvez l’utiliser pour extraire des données de presque n’importe quel fichier texte. Cependant, vous devez comprendre comment utiliser ses différentes options.
Sans options, voici ce que nous obtenons.
df = pd.read_csv(datafile)
df.head()
Pandas n’a pas réussi à identifier les différentes colonnes. C’est parce qu’il s’attendait à un fichier standard [CSV
(comma-separated values)] (https://en.wikipedia.org/wiki/Comma-separated_values). Dans notre fichier, au contraire, les valeurs sont séparées par des espaces. Et pas un seul espace blanc - la quantité d’espace blanc entre les valeurs varie. Nous pouvons l’indiquer à pandas en utilisant le mot-clé sep
.
df = pd.read_csv(datafile, sep='\s+')
df.head()
C’est génial ! Cela a fonctionné.
Si nous regardons de près, nous verrons qu’il y a beaucoup de valeurs -99 et -9999 dans le fichier. Le fichier README nous indique qu’il s’agit de valeurs utilisées pour représenter les données manquantes. Indiquons-le à pandas.
df = pd.read_csv(datafile, sep='\s+', na_values=[-9999.0, -99.0])
df.head()
Merveilleux. Les données manquantes sont maintenant représentées par NaN
.
Quels types de données pandas a-t-il déduits ?
df.info()
df = pd.read_csv(datafile, sep='\s+',
na_values=[-9999.0, -99.0],
parse_dates=[1])
df.info()
# Cela a fonctionné ! Enfin, demandons à pandas d'utiliser la colonne date comme index.
df = df.set_index('LST_DATE')
df.head()
df.loc['2017-08-07']
df.loc['2017-07-01':'2017-07-11']
2.6.2.8. Statistiques rapides#
Pandas intègre une fonction [boxplot
] (https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.boxplot.html) très pratique :
fig, ax = plt.subplots(ncols=2, nrows=2, figsize=(14,14))
df.iloc[:, 4:8].boxplot(ax=ax[0,0])
df.iloc[:, 10:14].boxplot(ax=ax[0,1])
df.iloc[:, 14:17].boxplot(ax=ax[1,0])
df.iloc[:, 18:22].boxplot(ax=ax[1,1])
ax[1, 1].set_xticklabels(ax[1, 1].get_xticklabels(), rotation=90);
# Pandas est "TIME-AWARE" (conscient du temps)
df.T_DAILY_MEAN.plot()
Note: nous pourrions également créer manuellement un axe et y tracer des courbes.
fig, ax = plt.subplots()
df.T_DAILY_MEAN.plot(ax=ax)
ax.set_title('Pandas Made This!')
df[['T_DAILY_MIN', 'T_DAILY_MEAN', 'T_DAILY_MAX']].plot()
2.6.2.9. Rééchantillonnage#
Puisque pandas
comprend le temps, nous pouvons l’utiliser pour faire du rééchantillonnage. La chaîne de fréquence de chaque décalage de date est listée [dans la documentation sur les séries temporelles] (https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#dateoffset-objects).
# Objet de rééchantillonnage mensuel
rs_obj = df.resample('MS')
rs_obj
rs_obj.mean()
# Nous pouvons enchaîner tout cela
df_mm = df.resample('MS').mean()
df_mm[['T_DAILY_MIN', 'T_DAILY_MEAN', 'T_DAILY_MAX']].plot()
Et ceci conclut le tutoriel de ce notebook 😀
Si vous souhaitez en savoir plus sur pandas
, consultez le tutoriel groupby
du Earth and Environmental Data Science book, le dépôt Github de Python for Data Analysis, ou les tutoriels de la communauté pandas
.