I. Quelques mots sur Pandas▲
La bibliothèque Pandas vise à intégrer les fonctionnalités de NumPy et matplotlib, pour vous donner un outil pratique pour analyser et visualiser les données. La bibliothèque Pandas va au-delà d'une simple intégration, elle améliore aussi l'utilisation.
Pour installer Pandas, exécutez la commande suivante en ligne de commande :
pip install pandasCette commande va charger et installer Pandas avec toutes ses dépendances, comme NumPy. Une fois cette bibliothèque installée, nous pouvons commencer notre exploration.
Les structures de données Pandas peuvent contenir tout type d'éléments : Series, DataFrame et Panel. Le facteur commun c'est que les structures de données sont étiquetées.
Dans ce tutoriel, nous utiliserons surtout DataFrame, mais voici une brève présentation de ces structures de données :
- Series - un objet étiqueté en forme de tableau unidimensionnel, capable de contenir n'importe quel type d'objet ;
- DataFrame - une structure de données bidimensionnelle où les colonnes peuvent être de différents types ;
- Panel - une structure de données tridimensionnelle. Vous pouvez les considérer comme des dictionnaires de DataFrames.
II. Fonctionnalités de base▲
Commençons par découvrir les fonctionnalités de base de la bibliothèque Pandas.
>>> import pandas as pd
>>> import numpy as np
>>> series = pd.Series([1,2,3,4,5, np.nan, "a string", 6])
>>> series
0 1
1 2
2 3
3 4
4 5
5 NaN
6 a string
7 6
dtype: objectDans l'exemple ci-dessus, nous avons créé un objet de type series qui contient plusieurs valeurs différentes. Un point intéressant à noter est que nous pouvons faire référence à des éléments de type not-a-number utilisant le symbole nan de NumPy qui nous indique que l'élément n'est pas un nombre, mais il peut être utilisé comme un type numérique. Le type des séries est un objet qui se réfère à ses contenus mixtes, car nous avons une chaîne incluse.
Si nous utilisons uniquement des types numériques, nous obtenons un dtype de base de Numpy, float pour notre série :
>>> series = pd.Series([1,2,np.nan, 4])
>>> series
0 1.0
1 2.0
2 NaN
3 4.0
dtype: float64Peu importe si les données intègrent un nan, la série sera traitée comme une série de nombres.
Mais le type qui nous intéresse n'est pas Series, mais DataFrames, car cela ressemble à un tableau à deux dimensions semblable à un fichier CSV ou à une table de base de données relationnelle :
>>> df = pd.DataFrame(np.array([1,2,3,4,5,6]).reshape(2,3))
>>> df
0 1 2
0 1 2 3
1 4 5 6
>>> df.dtypes
0 int32
1 int32
2 int32
dtype: objectLe paramétrage par défaut affiche l'indice numérique des lignes et des colonnes, mais il peut être modifié pour donner plus de sens aux données :
>>> df = pd.DataFrame(np.array([1,2,3,4,5,6]).reshape(2,3), columns=list('ABC'), index=list('XY'))
>>> df
A B C
X 1 2 3
Y 4 5 6Comme vous pouvez le voir, l'argument index fournit la liste à utiliser pour les lignes, alors que la liste fournie par l'argument columns peut être utilisée pour modifier les indices des colonnes.
Si nous avons des ensembles de données plus volumineux, la méthode head() peut aussi être utile. Elle affiche les n premières lignes fournies comme argument. Si vous ne fournissez pas d'argument, la valeur par défaut sera 5 :
>>> df2 = pd.DataFrame(np.arange(1, 7501).reshape(500,15))
>>> df2.head(2)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
>>> df2.head()
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
2 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
3 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
4 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75Le contraire est la méthode tail(). Elle affiche les n dernières lignes du DataFrame. Si vous omettez l'argument, la valeur par défaut utilisée sera 5 :
>>> df2.tail()
0 1 2 3 4 5 6 7 8 9 10 11 \
495 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437
496 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452
497 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467
498 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482
499 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497
12 13 14
495 7438 7439 7440
496 7453 7454 7455
497 7468 7469 7470
498 7483 7484 7485
499 7498 7499 7500
>>> df2.tail(1)
0 1 2 3 4 5 6 7 8 9 10 11 \
499 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497
12 13 14
499 7498 7499 7500Comme vous pouvez le voir, les colonnes sont réparties sur plusieurs lignes si elles sont trop larges, mais cela ne nous dérangera pas pour la suite, car nous n'afficherons pas nos données sur la console, mais nous utiliserons des visualisations pour afficher le résultat.
III. Description des données▲
La fonction describe est la fonctionnalité que nous allons fréquemment utiliser pour analyser un nouvel ensemble de données :
>>> df3 = pd.DataFrame(np.arange(1, 100, 0.12).reshape(33,25))
>>> df3.describe()
0 1 2 3 4 5 \
count 33.000000 33.000000 33.000000 33.000000 33.000000 33.000000
mean 49.000000 49.120000 49.240000 49.360000 49.480000 49.600000
std 29.008619 29.008619 29.008619 29.008619 29.008619 29.008619
min 1.000000 1.120000 1.240000 1.360000 1.480000 1.600000
25% 25.000000 25.120000 25.240000 25.360000 25.480000 25.600000
50% 49.000000 49.120000 49.240000 49.360000 49.480000 49.600000
75% 73.000000 73.120000 73.240000 73.360000 73.480000 73.600000
max 97.000000 97.120000 97.240000 97.360000 97.480000 97.600000
6 7 8 9 ... 15 \
count 33.000000 33.000000 33.000000 33.000000 ... 33.000000
mean 49.720000 49.840000 49.960000 50.080000 ... 50.800000
std 29.008619 29.008619 29.008619 29.008619 ... 29.008619
min 1.720000 1.840000 1.960000 2.080000 ... 2.800000
25% 25.720000 25.840000 25.960000 26.080000 ... 26.800000
50% 49.720000 49.840000 49.960000 50.080000 ... 50.800000
75% 73.720000 73.840000 73.960000 74.080000 ... 74.800000
max 97.720000 97.840000 97.960000 98.080000 ... 98.800000
16 17 18 19 20 21 \
count 33.000000 33.000000 33.000000 33.000000 33.000000 33.000000
mean 50.920000 51.040000 51.160000 51.280000 51.400000 51.520000
std 29.008619 29.008619 29.008619 29.008619 29.008619 29.008619
min 2.920000 3.040000 3.160000 3.280000 3.400000 3.520000
25% 26.920000 27.040000 27.160000 27.280000 27.400000 27.520000
50% 50.920000 51.040000 51.160000 51.280000 51.400000 51.520000
75% 74.920000 75.040000 75.160000 75.280000 75.400000 75.520000
max 98.920000 99.040000 99.160000 99.280000 99.400000 99.520000
22 23 24
count 33.000000 33.000000 33.000000
mean 51.640000 51.760000 51.880000
std 29.008619 29.008619 29.008619
min 3.640000 3.760000 3.880000
25% 27.640000 27.760000 27.880000
50% 51.640000 51.760000 51.880000
75% 75.640000 75.760000 75.880000
max 99.640000 99.760000 99.880000
[8 lignes * 25 colonnes]Comme vous pouvez le constater, l'appel de la méthode describe() sur le DataFrame affiche un bref résumé sur chaque colonne dans l'ensemble de données : le nombre d'éléments (count), leur moyenne, l'écart-type (std), les valeurs minimales et maximales et certaines autres valeurs.
IV. Indexation et partage▲
Pour sectionner une partie d'un Dataframe, il faut utiliser l'attribut iloc :
>>> df3 = pd.DataFrame(np.arange(1, 100, 0.12).reshape(33,25))
>>> df3.iloc[:5,:10]
0 1 2 3 4 5 6 7 8 9
0 1.0 1.12 1.24 1.36 1.48 1.6 1.72 1.84 1.96 2.08
1 4.0 4.12 4.24 4.36 4.48 4.6 4.72 4.84 4.96 5.08
2 7.0 7.12 7.24 7.36 7.48 7.6 7.72 7.84 7.96 8.08
3 10.0 10.12 10.24 10.36 10.48 10.6 10.72 10.84 10.96 11.08
4 13.0 13.12 13.24 13.36 13.48 13.6 13.72 13.84 13.96 14.08Dans l'exemple ci-dessus, nous avons sélectionné les 5 premières lignes et les 10 premières colonnes. Nous pouvons implémenter les méthodes head() et tail() en utilisant 5 comme le nombre de lignes par défaut avec iloc aussi :
>>> df3.iloc[-5:] # df3.tail(5)
0 1 2 3 4 5 6 7 8 9 ... \
28 85.0 85.12 85.24 85.36 85.48 85.6 85.72 85.84 85.96 86.08 ...
29 88.0 88.12 88.24 88.36 88.48 88.6 88.72 88.84 88.96 89.08 ...
30 91.0 91.12 91.24 91.36 91.48 91.6 91.72 91.84 91.96 92.08 ...
31 94.0 94.12 94.24 94.36 94.48 94.6 94.72 94.84 94.96 95.08 ...
32 97.0 97.12 97.24 97.36 97.48 97.6 97.72 97.84 97.96 98.08 ...
15 16 17 18 19 20 21 22 23 24
28 86.8 86.92 87.04 87.16 87.28 87.4 87.52 87.64 87.76 87.88
29 89.8 89.92 90.04 90.16 90.28 90.4 90.52 90.64 90.76 90.88
30 92.8 92.92 93.04 93.16 93.28 93.4 93.52 93.64 93.76 93.88
31 95.8 95.92 96.04 96.16 96.28 96.4 96.52 96.64 96.76 96.88
32 98.8 98.92 99.04 99.16 99.28 99.4 99.52 99.64 99.76 99.88
5 lignes * 25 colonnes>>> df3.iloc[:5] # df3.head(5)
0 1 2 3 4 5 6 7 8 9 ... \
0 1.0 1.12 1.24 1.36 1.48 1.6 1.72 1.84 1.96 2.08 ...
1 4.0 4.12 4.24 4.36 4.48 4.6 4.72 4.84 4.96 5.08 ...
2 7.0 7.12 7.24 7.36 7.48 7.6 7.72 7.84 7.96 8.08 ...
3 10.0 10.12 10.24 10.36 10.48 10.6 10.72 10.84 10.96 11.08 ...
4 13.0 13.12 13.24 13.36 13.48 13.6 13.72 13.84 13.96 14.08 ...
15 16 17 18 19 20 21 22 23 24
0 2.8 2.92 3.04 3.16 3.28 3.4 3.52 3.64 3.76 3.88
1 5.8 5.92 6.04 6.16 6.28 6.4 6.52 6.64 6.76 6.88
2 8.8 8.92 9.04 9.16 9.28 9.4 9.52 9.64 9.76 9.88
3 11.8 11.92 12.04 12.16 12.28 12.4 12.52 12.64 12.76 12.88
4 14.8 14.92 15.04 15.16 15.28 15.4 15.52 15.64 15.76 15.88
5 lignes * 25 colonnesMais Pandas va plus loin et nous permet d'accéder aux données via des labels (étiquettes) dans DataFrames. Cet exemple n'est pas très spectaculaire, car les labels de l'ensemble des données sont identiques à celles de leur position. Cependant, en utilisant la méthode rename, nous pouvons facilement renommer les colonnes du DataFrame et nous pouvons utiliser ces indices pour accéder aux valeurs :
>>> df4 = df3.rename(columns=lambda c: chr(65+c))
>>> df4.loc[:5, 'A':'D']
A B C D
0 1.0 1.12 1.24 1.36
1 4.0 4.12 4.24 4.36
2 7.0 7.12 7.24 7.36
3 10.0 10.12 10.24 10.36
4 13.0 13.12 13.24 13.36
5 16.0 16.12 16.24 16.36
>>> df4.loc[:5, ('A','D')]
A D
0 1.0 1.36
1 4.0 4.36
2 7.0 7.36
3 10.0 10.36
4 13.0 13.36
5 16.0 16.36Le point le plus intéressant est la fonction lambda fournie pour les noms des colonnes. C'est parce que vous avez besoin soit d'un paramètre semblable à un dictionnaire, soit d'une fonction qui renomme les labels. La création d'un dictionnaire alourdirait considérablement l'exemple, si bien qu'une fonction anonyme simple est une solution idéale. La fonction chr() renvoie la représentation en caractères du nombre fourni, chr(65) est égal au caractère A. Le paramètre c est l'en-tête actuel de l'axe (dans ce cas, les colonnes), qui est un nombre de 0 à 24.
Voilà quelque chose qui nous sera bien utile quand nous traiterons les données de fichiers CSV.
V. Lecture de fichiers CSV▲
À présent nous allons aborder certains exemples du monde réel. Nous utiliserons le même jeu de données que lors du dernier article sur NumPy. Si vous ne l'avez pas lu ou simplement ne voulez pas le chercher, le fichier est disponible au téléchargement : Les noms de bébé les plus fréquents selon le sexe et le groupe ethnique de la mère, New York City.
Je l'ai enregistré sous le nom baby_names.csv.
Il contient des prénoms donnés aux bébés de la ville de New York, selon le sexe et l'appartenance ethnique. Commençons par lire le fichier:
>>> import numpy as np
>>> import pandas as pd
>>> baby_names = pd.read_csv('baby_names.csv')
>>> baby_names.head()
BRTH_YR GNDR ETHCTY NM CNT RNK
0 2011 FEMALE HISPANIC GERALDINE 13 75
1 2011 FEMALE HISPANIC GIA 21 67
2 2011 FEMALE HISPANIC GIANNA 49 42
3 2011 FEMALE HISPANIC GISELLE 38 51
4 2011 FEMALE HISPANIC GRACE 36 53
>>> baby_names.tail()
BRTH_YR GNDR ETHCTY NM CNT RNK
13957 2014 MALE WHITE NON HISPANIC Yousef 18 94
13958 2014 MALE WHITE NON HISPANIC Youssef 24 88
13959 2014 MALE WHITE NON HISPANIC Yusuf 16 96
13960 2014 MALE WHITE NON HISPANIC Zachary 90 39
13961 2014 MALE WHITE NON HISPANIC Zev 49 65Vous pouvez voir que la lecture d'un fichier CSV se fait avec la fonction read_csv. Le résultat est un DataFrame et contrairement à NumPy, nous n'avons pas eu à dire à Pandas de lire toutes les données sous le format Strings. Cela signifie que les colonnes contenant des valeurs numériques ont des types numériques dans le DataFrame. Nous pouvons vérifier cela si nous regardons la description du DataFrame :
>>> baby_names.describe()
BRTH_YR CNT RNK
count 13962.000000 13962.000000 13962.000000
mean 2011.880318 34.531657 56.944349
std 1.134940 40.176370 25.361691
min 2011.000000 10.000000 1.000000
25% 2011.000000 13.000000 38.000000
50% 2011.000000 20.000000 59.000000
75% 2013.000000 36.000000 78.000000
max 2014.000000 426.000000 102.000000Vous pouvez voir que describe() sélectionne uniquement les colonnes qui ont des données numériques. Naturellement, certaines informations n'ont aucun sens, comme la colonne RNK (seul le count est utile) ou la moyenne et la fréquence dans BRTH_YR.
Vous avez peut-être remarqué que les colonnes du DataFrame contiennent des étiquettes identiques aux en-têtes du fichier CSV. C'est une fonctionnalité intéressante dans Pandas qui devient utile lorsque vous n'avez pas besoin de connaître l'indice de la colonne à laquelle vous souhaitez accéder.
Les DataFrames peuvent être triés selon des colonnes ou des axes et la forme sera maintenue après le tri. Maintenant, nous avons un ensemble de données réel, alors essayons le tri. Voyons les cinq premiers noms avec le nombre le plus bas et le plus élevé dans toutes les données (rappelez-vous : nous avons des années de 2011 à 2014 - le tri ne tient compte que du minimum et du maximum sur la base des données de chaque année et ne regroupe pas les mêmes noms sur plusieurs années) :
>>> baby_names.head()
BRTH_YR GNDR ETHCTY NM CNT RNK
0 2011 FEMALE HISPANIC GERALDINE 13 75
1 2011 FEMALE HISPANIC GIA 21 67
2 2011 FEMALE HISPANIC GIANNA 49 42
3 2011 FEMALE HISPANIC GISELLE 38 51
4 2011 FEMALE HISPANIC GRACE 36 53
>>> baby_names.sort_values(by='CNT').head()
BRTH_YR GNDR ETHCTY NM CNT RNK
8744 2012 FEMALE WHITE NON HISP MAE 10 83
6746 2011 FEMALE WHITE NON HISPANIC LEILA 10 81
2389 2011 MALE HISPANIC ALLAN 10 94
11009 2013 MALE ASIAN AND PACIFIC ISLANDER Martin 10 57
11013 2013 MALE ASIAN AND PACIFIC ISLANDER Maximilian 10 57
>>> baby_names.sort_values(by='CNT', ascending=False).head()
BRTH_YR GNDR ETHCTY NM CNT RNK
1504 2011 MALE HISPANIC JAYDEN 426 1
5430 2011 MALE HISPANIC JAYDEN 426 1
7393 2011 MALE HISPANIC JAYDEN 426 1
3505 2011 MALE HISPANIC JAYDEN 426 1
9385 2012 MALE HISPANIC JAYDEN 364 1Comme vous pouvez le voir, nous avons identifié un problème dans notre jeu de données : nous avons des entrées qui ont le même contenu. Cela rend nos données moins utilisables en l'état et nous devons les retraiter pour obtenir un résultat exploitable. Mais c'est une bonne chose en science des données et nous allons examiner une méthode de filtrage des doublons.
VI. Conclusion▲
Nous avons vu que la bibliothèque Pandas est la suite logique de NumPy dans l'analyse de données avec Python, car elle nous permet de gérer les données de manière optimale. Cependant, nous ne pouvons pas ignorer NumPy parce que Pandas s'appuie sur NumPy et Matplotlib pour nous donner un point de vue unique vous permettant d'effectuer votre analyse de données et votre visualisation. Pandas apporte vraiment un plus si nous importons des fichiers CSV avec un contenu mixte : vous n'avez pas à vous soucier des conversions.
VII. Remerciements▲
Nous remercions Gabor Laszlo Hajba de nous avoir autorisés à publier son tutoriel Introduction to Pandas - Data Analysis in Python
Nous tenons également à remercier Laethy pour la traduction de ce tutoriel, Lolo78 pour la revue de la traduction et Claude Leloup pour la correction orthographique.



