18. Pandas pour les données de panel#

En plus de ce qui est inclus dans Anaconda, ce cours nécessitera les bibliothèques suivantes :

!pip install --upgrade seaborn

Hide code cell output

Requirement already satisfied: seaborn in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (0.13.2)
Requirement already satisfied: numpy!=1.24.0,>=1.20 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from seaborn) (2.4.6)
Requirement already satisfied: pandas>=1.2 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from seaborn) (3.0.3)
Requirement already satisfied: matplotlib!=3.6.1,>=3.4 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from seaborn) (3.10.9)
Requirement already satisfied: contourpy>=1.0.1 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (4.63.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.4.9)
Requirement already satisfied: packaging>=20.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (26.0)
Requirement already satisfied: pillow>=8 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (12.2.0)
Requirement already satisfied: pyparsing>=3 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (3.2.5)
Requirement already satisfied: python-dateutil>=2.7 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (2.9.0.post0)
Requirement already satisfied: six>=1.5 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from python-dateutil>=2.7->matplotlib!=3.6.1,>=3.4->seaborn) (1.17.0)

Nous utilisons les importations suivantes.

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()

18.1. Vue d’ensemble#

Dans un cours précédent sur pandas, nous avons examiné le travail avec des ensembles de données simples.

Les économètres ont souvent besoin de travailler avec des ensembles de données plus complexes, comme les panels.

Les tâches courantes comprennent

  • Importer des données, les nettoyer et les remodeler selon plusieurs axes.

  • Sélectionner une série temporelle ou une coupe transversale à partir d’un panel.

  • Grouper et résumer des données.

pandas (dérivé de « panel » et « data ») contient des outils puissants et faciles à utiliser pour résoudre exactement ce genre de problèmes.

Dans ce qui suit, nous utiliserons un ensemble de données de panel des salaires minimums réels de l’OCDE pour créer :

  • des statistiques descriptives sur plusieurs dimensions de nos données

  • une série temporelle du salaire minimum moyen des pays de l’ensemble de données

  • des estimations par noyau de la densité des salaires par continent

Nous commencerons par lire nos données de panel au format long à partir d’un fichier CSV et par remodeler le DataFrame résultant avec pivot_table afin de construire un MultiIndex.

Des détails supplémentaires seront ajoutés à notre DataFrame en utilisant la fonction merge de pandas, et les données seront résumées avec la fonction groupby.

18.2. Découpage et remodelage des données#

Nous allons lire un ensemble de données de l’OCDE des salaires minimums réels dans 32 pays et l’assigner à realwage.

L’ensemble de données est accessible via le lien suivant :

url1 = 'https://github.com/QuantEcon/data-lectures/raw/main/lectures/realwage.csv'
import pandas as pd

# Afficher 6 colonnes à des fins de visualisation
pd.set_option('display.max_columns', 6)

# Réduire les décimales à 2
pd.options.display.float_format = '{:,.2f}'.format

realwage = pd.read_csv(url1)

Regardons ce avec quoi nous devons travailler

realwage.head()  # Afficher les 5 premières lignes
Unnamed: 0 Time Country Series Pay period value
0 0 2006-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 17,132.44
1 1 2007-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 18,100.92
2 2 2008-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 17,747.41
3 3 2009-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 18,580.14
4 4 2010-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 18,755.83

Les données sont actuellement au format long, ce qui est difficile à analyser lorsque les données comportent plusieurs dimensions.

Nous utiliserons pivot_table pour créer un panel au format large, avec un MultiIndex pour gérer les données de dimension supérieure.

Les arguments de pivot_table doivent spécifier les données (values), l’index et les colonnes que nous voulons dans notre dataframe résultant.

En passant une liste dans columns, nous pouvons créer un MultiIndex dans notre axe des colonnes

realwage = realwage.pivot_table(values='value',
                                index='Time',
                                columns=['Country', 'Series', 'Pay period'])
realwage.head()
Country Australia ... United States
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates ... In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual ... Hourly Annual Hourly
Time
2006-01-01 20,410.65 10.33 23,826.64 ... 6.05 12,594.40 6.05
2007-01-01 21,087.57 10.67 24,616.84 ... 6.24 12,974.40 6.24
2008-01-01 20,718.24 10.48 24,185.70 ... 6.78 14,097.56 6.78
2009-01-01 20,984.77 10.62 24,496.84 ... 7.58 15,756.42 7.58
2010-01-01 20,879.33 10.57 24,373.76 ... 7.88 16,391.31 7.88

5 rows × 128 columns

Pour filtrer plus facilement nos données de série temporelle par la suite, nous convertirons l’index en DateTimeIndex

realwage.index = pd.to_datetime(realwage.index)
type(realwage.index)
pandas.DatetimeIndex

Les colonnes contiennent plusieurs niveaux d’indexation, appelés MultiIndex, les niveaux étant ordonnés hiérarchiquement (Country > Series > Pay period).

Un MultiIndex est le moyen le plus simple et le plus flexible de gérer les données de panel dans pandas

type(realwage.columns)
pandas.MultiIndex
realwage.columns.names
FrozenList(['Country', 'Series', 'Pay period'])

Comme précédemment, nous pouvons sélectionner le pays (le niveau le plus élevé de notre MultiIndex)

realwage['United States'].head()
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual Hourly
Time
2006-01-01 12,594.40 6.05 12,594.40 6.05
2007-01-01 12,974.40 6.24 12,974.40 6.24
2008-01-01 14,097.56 6.78 14,097.56 6.78
2009-01-01 15,756.42 7.58 15,756.42 7.58
2010-01-01 16,391.31 7.88 16,391.31 7.88

L’empilement et le désempilement des niveaux du MultiIndex seront utilisés tout au long de ce cours pour remodeler notre dataframe dans le format dont nous avons besoin.

.stack() fait pivoter le niveau le plus bas du MultiIndex des colonnes vers l’index des lignes (.unstack() fonctionne dans la direction opposée — essayez-le)

realwage.stack(future_stack=True).head()
Country Australia Belgium ... United Kingdom United States
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates In 2015 constant prices at 2015 USD PPPs ... In 2015 constant prices at 2015 USD exchange rates In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Time Pay period
2006-01-01 Annual 20,410.65 23,826.64 21,042.28 ... 20,376.32 12,594.40 12,594.40
Hourly 10.33 12.06 10.09 ... 9.81 6.05 6.05
2007-01-01 Annual 21,087.57 24,616.84 21,310.05 ... 20,954.13 12,974.40 12,974.40
Hourly 10.67 12.46 10.22 ... 10.07 6.24 6.24
2008-01-01 Annual 20,718.24 24,185.70 21,416.96 ... 20,902.87 14,097.56 14,097.56

5 rows × 64 columns

Nous pouvons également passer un argument pour sélectionner le niveau que nous aimerions empiler

realwage.stack(level='Country', future_stack=True).head()  # future_stack=True est requis jusqu'à pandas>3.0
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual Hourly
Time Country
2006-01-01 Australia 20,410.65 10.33 23,826.64 12.06
Belgium 21,042.28 10.09 20,228.74 9.70
Brazil 3,310.51 1.41 2,032.87 0.87
Canada 13,649.69 6.56 14,335.12 6.89
Chile 5,201.65 2.22 3,333.76 1.42

L’utilisation d’un DatetimeIndex facilite la sélection d’une période temporelle particulière.

Sélectionner une année et empiler les deux niveaux inférieurs du MultiIndex crée une coupe transversale de nos données de panel

realwage.loc['2015'].stack(level=(1, 2), future_stack=True).transpose().head() # future_stack=True est requis jusqu'à pandas>3.0
Time 2015-01-01
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual Hourly
Country
Australia 21,715.53 10.99 25,349.90 12.83
Belgium 21,588.12 10.35 20,753.48 9.95
Brazil 4,628.63 2.00 2,842.28 1.21
Canada 16,536.83 7.95 17,367.24 8.35
Chile 6,633.56 2.80 4,251.49 1.81

Pour le reste du cours, nous travaillerons avec un dataframe des salaires minimums réels horaires par pays et par période, mesurés en dollars américains de 2015.

Pour créer notre dataframe filtré (realwage_f), nous pouvons utiliser la méthode xs pour sélectionner des valeurs aux niveaux inférieurs du multiindex, tout en conservant les niveaux supérieurs (les pays dans ce cas)

realwage_f = realwage.xs(('Hourly', 'In 2015 constant prices at 2015 USD exchange rates'),
                         level=('Pay period', 'Series'), axis=1)
realwage_f.head()
Country Australia Belgium Brazil ... Turkey United Kingdom United States
Time
2006-01-01 12.06 9.70 0.87 ... 2.27 9.81 6.05
2007-01-01 12.46 9.82 0.92 ... 2.26 10.07 6.24
2008-01-01 12.24 9.87 0.96 ... 2.22 10.04 6.78
2009-01-01 12.40 10.21 1.03 ... 2.28 10.15 7.58
2010-01-01 12.34 10.05 1.08 ... 2.30 9.96 7.88

5 rows × 32 columns

18.3. Fusion de dataframes et remplissage des NaN#

Similairement aux bases de données relationnelles comme SQL, pandas dispose de méthodes intégrées pour fusionner des ensembles de données ensemble.

En utilisant les informations sur les pays de WorldData.info, nous ajouterons le continent de chaque pays à realwage_f avec la fonction merge.

L’ensemble de données est accessible via le lien suivant :

url2 = 'https://github.com/QuantEcon/data-lectures/raw/main/lectures/countries.csv'
worlddata = pd.read_csv(url2, sep=';')
worlddata.head()
Country (en) Country (de) Country (local) ... Deathrate Life expectancy Url
0 Afghanistan Afghanistan Afganistan/Afqanestan ... 13.70 51.30 https://www.laenderdaten.info/Asien/Afghanista...
1 Egypt Ägypten Misr ... 4.70 72.70 https://www.laenderdaten.info/Afrika/Aegypten/...
2 Åland Islands Ålandinseln Åland ... 0.00 0.00 https://www.laenderdaten.info/Europa/Aland/ind...
3 Albania Albanien Shqipëria ... 6.70 78.30 https://www.laenderdaten.info/Europa/Albanien/...
4 Algeria Algerien Al-Jaza’ir/Algérie ... 4.30 76.80 https://www.laenderdaten.info/Afrika/Algerien/...

5 rows × 17 columns

Tout d’abord, nous sélectionnerons uniquement les variables country et continent de worlddata et renommerons la colonne en « Country »

worlddata = worlddata[['Country (en)', 'Continent']]
worlddata = worlddata.rename(columns={'Country (en)': 'Country'})
worlddata.head()
Country Continent
0 Afghanistan Asia
1 Egypt Africa
2 Åland Islands Europe
3 Albania Europe
4 Algeria Africa

Nous voulons fusionner notre nouveau dataframe, worlddata, avec realwage_f.

La fonction merge de pandas permet de joindre des dataframes ensemble par lignes.

Nos dataframes seront fusionnés en utilisant les noms de pays, ce qui nous oblige à utiliser la transposée de realwage_f afin que les lignes correspondent aux noms de pays dans les deux dataframes

realwage_f.transpose().head()
Time 2006-01-01 2007-01-01 2008-01-01 ... 2014-01-01 2015-01-01 2016-01-01
Country
Australia 12.06 12.46 12.24 ... 12.67 12.83 12.98
Belgium 9.70 9.82 9.87 ... 10.01 9.95 9.76
Brazil 0.87 0.92 0.96 ... 1.21 1.21 1.24
Canada 6.89 6.96 7.24 ... 8.22 8.35 8.48
Chile 1.42 1.45 1.44 ... 1.76 1.81 1.91

5 rows × 11 columns

Nous pouvons utiliser une jointure left, right, inner ou outer pour fusionner nos ensembles de données :

  • la jointure left n’inclut que les pays de l’ensemble de données de gauche

  • la jointure right n’inclut que les pays de l’ensemble de données de droite

  • la jointure outer inclut les pays qui sont soit dans l’ensemble de gauche, soit dans celui de droite

  • la jointure inner n’inclut que les pays communs aux deux ensembles de données de gauche et de droite

Par défaut, merge utilisera une jointure inner.

Ici, nous passerons how='left' pour conserver tous les pays de realwage_f, mais écarter les pays de worlddata qui n’ont pas d’entrée de données correspondante dans realwage_f.

Ceci est illustré par la zone ombrée en rouge dans le diagramme suivant

_images/venn_diag.png

Nous devrons également spécifier où se trouve le nom du pays dans chaque dataframe, qui sera la key utilisée pour fusionner les dataframes (« on »).

Notre dataframe « left » (realwage_f.transpose()) contient les pays dans l’index, donc nous définissons left_index=True.

Notre dataframe « right » (worlddata) contient les pays dans la colonne « Country », donc nous définissons right_on='Country'

merged = pd.merge(realwage_f.transpose(), worlddata,
                  how='left', left_index=True, right_on='Country')
merged.head()
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2016-01-01 00:00:00 Country Continent
17.00 12.06 12.46 12.24 ... 12.98 Australia Australia
23.00 9.70 9.82 9.87 ... 9.76 Belgium Europe
32.00 0.87 0.92 0.96 ... 1.24 Brazil South America
100.00 6.89 6.96 7.24 ... 8.48 Canada North America
38.00 1.42 1.45 1.44 ... 1.91 Chile South America

5 rows × 13 columns

Les pays qui apparaissaient dans realwage_f mais pas dans worlddata auront NaN dans la colonne Continent.

Pour vérifier si cela s’est produit, nous pouvons utiliser .isnull() sur la colonne continent et filtrer le dataframe fusionné

merged[merged['Continent'].isnull()]
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2016-01-01 00:00:00 Country Continent
NaN 3.42 3.74 3.87 ... 5.28 Korea NaN
NaN 0.23 0.45 0.39 ... 0.55 Russian Federation NaN
NaN 1.50 1.64 1.71 ... 2.08 Slovak Republic NaN

3 rows × 13 columns

Nous avons trois valeurs manquantes !

Une option pour traiter les valeurs NaN consiste à créer un dictionnaire contenant ces pays et leurs continents respectifs.

.map() fera correspondre les pays de merged['Country'] avec leur continent à partir du dictionnaire.

Remarquez comment les pays qui ne figurent pas dans notre dictionnaire sont mappés avec NaN

missing_continents = {'Korea': 'Asia',
                      'Russian Federation': 'Europe',
                      'Slovak Republic': 'Europe'}

merged['Country'].map(missing_continents)
17.00        NaN
23.00        NaN
32.00        NaN
100.00       NaN
38.00        NaN
108.00       NaN
41.00        NaN
225.00       NaN
53.00        NaN
58.00        NaN
45.00        NaN
68.00        NaN
233.00       NaN
86.00        NaN
88.00        NaN
91.00        NaN
NaN         Asia
117.00       NaN
122.00       NaN
123.00       NaN
138.00       NaN
153.00       NaN
151.00       NaN
174.00       NaN
175.00       NaN
NaN       Europe
NaN       Europe
198.00       NaN
200.00       NaN
227.00       NaN
241.00       NaN
240.00       NaN
Name: Country, dtype: str

Nous ne voulons pas écraser toute la série avec ce mappage.

.fillna() ne remplit que les valeurs NaN dans merged['Continent'] avec le mappage, tout en laissant les autres valeurs de la colonne inchangées

merged['Continent'] = merged['Continent'].fillna(merged['Country'].map(missing_continents))

# Vérifier si les continents ont été correctement mappés

merged[merged['Country'] == 'Korea']
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2016-01-01 00:00:00 Country Continent
NaN 3.42 3.74 3.87 ... 5.28 Korea Asia

1 rows × 13 columns

Nous combinerons également les Amériques en un seul continent — cela rendra notre visualisation plus agréable par la suite.

Pour ce faire, nous utiliserons .replace() et boucler sur une liste des valeurs de continent que nous voulons remplacer

replace = ['Central America', 'North America', 'South America']
merged['Continent'] = merged['Continent'].replace(to_replace=replace, value='America')

Maintenant que nous avons toutes les données que nous voulons dans un seul DataFrame, nous allons le remodeler à nouveau sous forme de panel avec un MultiIndex.

Nous devrions également veiller à trier l’index en utilisant .sort_index() afin de pouvoir filtrer efficacement notre dataframe par la suite.

Par défaut, les niveaux seront triés de haut en bas

merged = merged.set_index(['Continent', 'Country']).sort_index()
merged.head()
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2014-01-01 00:00:00 2015-01-01 00:00:00 2016-01-01 00:00:00
Continent Country
America Brazil 0.87 0.92 0.96 ... 1.21 1.21 1.24
Canada 6.89 6.96 7.24 ... 8.22 8.35 8.48
Chile 1.42 1.45 1.44 ... 1.76 1.81 1.91
Colombia 1.01 1.02 1.01 ... 1.13 1.13 1.12
Costa Rica NaN NaN NaN ... 2.41 2.56 2.63

5 rows × 11 columns

Lors de la fusion, nous avons perdu notre DatetimeIndex, car nous avons fusionné des colonnes qui n’étaient pas au format datetime

merged.columns
Index([2006-01-01 00:00:00, 2007-01-01 00:00:00, 2008-01-01 00:00:00,
       2009-01-01 00:00:00, 2010-01-01 00:00:00, 2011-01-01 00:00:00,
       2012-01-01 00:00:00, 2013-01-01 00:00:00, 2014-01-01 00:00:00,
       2015-01-01 00:00:00, 2016-01-01 00:00:00],
      dtype='object')

Maintenant que nous avons défini les colonnes fusionnées comme index, nous pouvons recréer un DatetimeIndex en utilisant .to_datetime()

merged.columns = pd.to_datetime(merged.columns)
merged.columns = merged.columns.rename('Time')
merged.columns
DatetimeIndex(['2006-01-01', '2007-01-01', '2008-01-01', '2009-01-01',
               '2010-01-01', '2011-01-01', '2012-01-01', '2013-01-01',
               '2014-01-01', '2015-01-01', '2016-01-01'],
              dtype='datetime64[us]', name='Time', freq=None)

Le DatetimeIndex a tendance à fonctionner plus harmonieusement dans l’axe des lignes, donc nous allons transposer merged

merged = merged.transpose()
merged.head()
Continent America ... Europe
Country Brazil Canada Chile ... Slovenia Spain United Kingdom
Time
2006-01-01 0.87 6.89 1.42 ... 3.92 3.99 9.81
2007-01-01 0.92 6.96 1.45 ... 3.88 4.10 10.07
2008-01-01 0.96 7.24 1.44 ... 3.96 4.14 10.04
2009-01-01 1.03 7.67 1.52 ... 4.08 4.32 10.15
2010-01-01 1.08 7.94 1.56 ... 4.81 4.30 9.96

5 rows × 32 columns

18.4. Groupement et synthèse des données#

Le groupement et la synthèse des données peuvent être particulièrement utiles pour comprendre les grands ensembles de données de panel.

Un moyen simple de résumer les données consiste à appeler une méthode d’agrégation sur le dataframe, comme .mean() ou .max().

Par exemple, nous pouvons calculer le salaire minimum réel moyen pour chaque pays sur la période de 2006 à 2016 (par défaut, l’agrégation se fait sur les lignes)

merged.mean().head(10)
Continent  Country      
America    Brazil          1.09
           Canada          7.82
           Chile           1.62
           Colombia        1.07
           Costa Rica      2.53
           Mexico          0.53
           United States   7.15
Asia       Israel          5.95
           Japan           6.18
           Korea           4.22
dtype: float64

En utilisant cette série, nous pouvons tracer le salaire minimum réel moyen au cours de la dernière décennie pour chaque pays de notre ensemble de données

merged.mean().sort_values(ascending=False).plot(kind='bar',
                                                title="Salaire minimum réel moyen 2006 - 2016")

# Définir les étiquettes de pays
country_labels = merged.mean().sort_values(ascending=False).index.get_level_values('Country').tolist()
plt.xticks(range(0, len(country_labels)), country_labels)
plt.xlabel('Pays')

plt.show()
_images/73c145cd516af3e3769a1c24f52f490d44ecb744c68757b9f8b90bab7e0570af.png

Passer axis=1 à .mean() agrégera sur les colonnes (donnant le salaire minimum moyen pour tous les pays au fil du temps)

merged.mean(axis=1).head()
Time
2006-01-01   4.69
2007-01-01   4.84
2008-01-01   4.90
2009-01-01   5.08
2010-01-01   5.11
dtype: float64

Nous pouvons tracer cette série temporelle sous forme de graphique linéaire

merged.mean(axis=1).plot()
plt.title('Salaire minimum réel moyen 2006 - 2016')
plt.ylabel('USD 2015')
plt.xlabel('Année')
plt.show()
_images/cc2d4ba3d5f5e77609777ab647b0b5092331df57eeae27657a97da11d5860667.png

Nous pouvons également spécifier un niveau du MultiIndex (dans l’axe des colonnes) sur lequel agréger.

Dans le cas de groupby, nous devons utiliser .T pour transposer les colonnes en lignes car pandas a déprécié l’utilisation de axis=1 dans la méthode groupby.

merged.T.groupby(level='Continent').mean().head()
Time 2006-01-01 2007-01-01 2008-01-01 ... 2014-01-01 2015-01-01 2016-01-01
Continent
America 2.80 2.85 2.99 ... 3.22 3.26 3.30
Asia 4.29 4.44 4.45 ... 4.86 5.10 5.44
Australia 10.25 10.73 10.76 ... 11.25 11.52 11.73
Europe 4.80 4.94 4.99 ... 5.17 5.48 5.57

4 rows × 11 columns

Nous pouvons tracer les salaires minimums moyens de chaque continent sous forme de série temporelle

merged.T.groupby(level='Continent').mean().T.plot()
plt.title('Salaire minimum réel moyen')
plt.ylabel('USD 2015')
plt.xlabel('Année')
plt.show()
_images/dca08e1bb9fc6b6e975464e91b8fcac1ebea6388f907c9967841bcdf428dd23a.png

Nous exclurons l’Australie en tant que continent à des fins de traçage

merged = merged.drop('Australia', level='Continent', axis=1)
merged.T.groupby(level='Continent').mean().T.plot()
plt.title('Salaire minimum réel moyen')
plt.ylabel('USD 2015')
plt.xlabel('Année')
plt.show()
_images/436f5d7fcfecd1cdd9309b28d1271b8525bf806025c7dd3796cd54e1c853e38c.png

.describe() est utile pour récupérer rapidement un certain nombre de statistiques descriptives courantes

merged.stack(future_stack=True).describe()
Continent America Asia Europe
count 69.00 44.00 200.00
mean 3.19 4.70 5.15
std 3.02 1.56 3.82
min 0.52 2.22 0.23
25% 1.03 3.37 2.02
50% 1.44 5.48 3.54
75% 6.96 5.95 9.70
max 8.48 6.65 12.39

Il s’agit d’une manière simplifiée d’utiliser groupby.

L’utilisation de groupby suit généralement un processus « diviser-appliquer-combiner » :

  • diviser : les données sont groupées en fonction d’une ou plusieurs clés

  • appliquer : une fonction est appelée sur chaque groupe indépendamment

  • combiner : les résultats des appels de fonction sont combinés dans une nouvelle structure de données

La méthode groupby réalise la première étape de ce processus, créant un nouvel objet DataFrameGroupBy avec les données divisées en groupes.

Divisons à nouveau merged par continent, cette fois en utilisant la fonction groupby, et nommons l’objet résultant grouped

grouped = merged.T.groupby(level='Continent')
grouped
<pandas.api.typing.DataFrameGroupBy object at 0x7ff515b872f0>

L’appel d’une méthode d’agrégation sur l’objet applique la fonction à chaque groupe, dont les résultats sont combinés dans une nouvelle structure de données.

Par exemple, nous pouvons retourner le nombre de pays de notre ensemble de données pour chaque continent en utilisant .size().

Dans ce cas, notre nouvelle structure de données est une Series

grouped.size()
Continent
America     7
Asia        4
Europe     19
dtype: int64

En appelant .get_group() pour retourner uniquement les pays d’un seul groupe, nous pouvons créer une estimation par noyau de la densité de la distribution des salaires minimums réels en 2016 pour chaque continent.

grouped.groups.keys() retournera les clés de l’objet groupby

continents = grouped.groups.keys()

for continent in continents:
    sns.kdeplot(grouped.get_group(continent).T.loc['2015'].unstack(), label=continent, fill=True)

plt.title('Salaires minimums réels en 2015')
plt.xlabel('Dollars américains')
plt.legend()
plt.show()
_images/2af19d7b097fae5e93cd850f8516215ff6cf34d5e5e23c91eab851f71b601fcb.png

18.5. Remarques finales#

Ce cours a fourni une introduction à certaines des fonctionnalités plus avancées de pandas, notamment les multiindices, la fusion, le groupement et le traçage.

D’autres outils qui peuvent être utiles dans l’analyse des données de panel comprennent xarray, un package python qui étend pandas aux structures de données à N dimensions.

18.6. Exercices#

Exercice 18.1

Dans ces exercices, vous travaillerez avec un ensemble de données de taux d’emploi en Europe par âge et par sexe provenant d”Eurostat.

L’ensemble de données est accessible via le lien suivant :

url3 = 'https://github.com/QuantEcon/data-lectures/raw/main/lectures/employ.csv'

La lecture du fichier CSV retourne un ensemble de données de panel au format long. Utilisez .pivot_table() pour construire un dataframe au format large avec un MultiIndex dans les colonnes.

Commencez par explorer le dataframe et les variables disponibles dans les niveaux du MultiIndex.

Écrivez un programme qui retourne rapidement toutes les valeurs du MultiIndex.

Exercice 18.2

Filtrez le dataframe ci-dessus pour n’inclure que l’emploi en pourcentage de la « population active ».

Créez un diagramme en boîte groupé en utilisant seaborn des taux d’emploi en 2015 par groupe d’âge et par sexe.