Première expérimentation avec la librairie Pandas en Python
Triangle de Fibonacci en DataFrame
Pour réaliser nos expérimentations de données gérées par la librairie Pandas, nous allons d’abord construire un tableau (appelé DataFrame en Pandas) d’un triangle de Fibonacci.
import pandas as pd
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
def generate_fibonacci_triangle(n):
triangle = []
for i in range(n):
row = [fibonacci(j) for j in range(i+1)]
triangle.append(row)
return triangle
n = 10
triangle = generate_fibonacci_triangle(n)
df = pd.DataFrame(triangle)
Nous importons d’abord la librairie Pandas. À l’aide de la fonction classique de la fonction de Fibonacci, nous générons d’abord un tableau Python de valeurs du triangle de Fibonacci.
Ensuite, à partir de ce tableau (qui est une liste de listes), nous générons un DataFrame.
>>> df
0 1 2 3 4 5 6 7 8 9
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
2 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
3 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
4 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
5 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
6 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
7 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
8 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
9 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
Son affichage présente un tableau formaté avec les indexes des lignes et de colonnes.
Information de base sur le DataFrame
Pour connaître les dimensions du DataFrame construit, nous utilisons l’attribut shape
. Nous pouvons récupérer le nombre de lignes et de colonnes
>>> df.shape
(10, 10)
>>> df.shape[0]
10
>>> df.shape[1]
10
Pour afficher les métadonnées du DataFrame, nous utilisons la méthode info()
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 0 10 non-null int64
1 1 9 non-null float64
2 2 8 non-null float64
3 3 7 non-null float64
4 4 6 non-null float64
5 5 5 non-null float64
6 6 4 non-null float64
7 7 3 non-null float64
8 8 2 non-null float64
9 9 1 non-null float64
dtypes: float64(9), int64(1)
memory usage: 928.0 bytes
Nous remarquons que les données sont typées. Étrangement, la première colonne est de type int64
et les autres de type fload64
. Nous allons corriger cela plus tard.
Notons que la structure est orientée colonne. Chaque colonne peut être un type de données particuliers. Les lignes représentent en quelque sorte les enregistrements.
Il est facile de faire l’analogie avec un chiffrier électronique où les colonnes auraient une en-tête donnée avec un type donnée. Une autre analogie est possible avec un table d’une base de données. Les attributs sont les colonnes et les enregistrements sont les lignes.
Avec la méthode describe()
, nous pouvons afficher des statistiques générales sous forme d’un DataFrame. Pour chaque colonne, nous obtenons:
- le décompte des valeurs numériques
- la moyenne
- l’écart-type
- la valeur minimum
- la valeur maximum
- le 25ième percentile
- le 50ième percentile
- le 75ième percentile
- la valeur maximale
Voici le résultat
>>> df.describe()
0 1 2 3 4 5 6 7 8 9
count 10.0 9.0 8.0 7.0 6.0 5.0 4.0 3.0 2.0 1.0
mean 0.0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
std 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 NaN
min 0.0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
25% 0.0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
50% 0.0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
75% 0.0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
max 0.0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
La méthode head()
permet d’afficher les premières lignes du Dataframe.
Sans paramètre, on obtient les 5 premières lignes:
df.head()
0 1 2 3 4 5 6 7 8 9
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
2 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
3 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
4 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
Nous pouvons préciser le nombre de lignes à afficher:
df.head(6)
0 1 2 3 4 5 6 7 8 9
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
2 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
3 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
4 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
5 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
La méthode tail()
permet d’afficher les dernières lignes.
df.tail()
0 1 2 3 4 5 6 7 8 9
5 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
6 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
7 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
8 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
9 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
Tri des lignes et des colonnes
Pour trier les lignes en ordre croissant, nous utilisons l’appel suivant:
df.sort_index()
0 1 2 3 4 5 6 7 8 9
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
2 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
3 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
4 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
5 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
6 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
7 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
8 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
9 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
Cela ne change rien puisque les lignes sont déjà ordonnées. Pour obtenir l’ordre inverse:
>>> df.sort_index(ascending=False)
0 1 2 3 4 5 6 7 8 9
9 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
8 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
7 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
6 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
5 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
4 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
3 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
2 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
Pour trier en ordre inverse les colonnes, voici comment:
>>> df.sort_index(ascending=False, axis=1)
9 8 7 6 5 4 3 2 1 0
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 0
1 NaN NaN NaN NaN NaN NaN NaN NaN 1.0 0
2 NaN NaN NaN NaN NaN NaN NaN 1.0 1.0 0
3 NaN NaN NaN NaN NaN NaN 2.0 1.0 1.0 0
4 NaN NaN NaN NaN NaN 3.0 2.0 1.0 1.0 0
5 NaN NaN NaN NaN 5.0 3.0 2.0 1.0 1.0 0
6 NaN NaN NaN 8.0 5.0 3.0 2.0 1.0 1.0 0
7 NaN NaN 13.0 8.0 5.0 3.0 2.0 1.0 1.0 0
8 NaN 21.0 13.0 8.0 5.0 3.0 2.0 1.0 1.0 0
9 34.0 21.0 13.0 8.0 5.0 3.0 2.0 1.0 1.0 0
Tri des données
Pour trier les données, nous devons préciser la colonne du tri. Les lignes seront alors triées en fonction de l’ordre de la colonne choisie. Les valeurs NaN (Not a Number) seront placées à la fin de la liste. Pour trier en focntion de l’indexe 1, voici comment faire:
>>> df.sort_values(by=[1])
0 1 2 3 4 5 6 7 8 9
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
2 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
3 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
4 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
5 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
6 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
7 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
8 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
9 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
Nous constatons que les indexes de ligne ont changé d’ordre en fonction du tri des valeurs réalisées.
Localiser une ligne
À l’aide de l’attribut iloc
, nous pouvons extraire une ou plusieurs lignes par les indexes comme par exemple:
>>> df.iloc[0]
0 0.0
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
6 NaN
7 NaN
8 NaN
9 NaN
Name: 0, dtype: float64
Nous pouvons aussi extraire un sous-ensemble des lignes comme par exemple:
>>> df.iloc[[0, 1]]
0 1 2 3 4 5 6 7 8 9
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
Si nous modifions l’ordre des lignes comme par exemple comme nous avons fait auparavant:
>>> nouveau_df = df.sort_values(by=[1])
0 1 2 3 4 5 6 7 8 9
1 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
2 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
3 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
4 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
5 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
6 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
7 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
8 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
9 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
0 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
Si nous utilisons iloc
pour obtenir la première ligne, nous obtenons la première ligne de cet nouvel ordre et non l’indexe 0
qu’on voit dans la liste ci-haut (qui est la dernière ligne en réalité):
nouveau_df.iloc[0]
0 0.0
1 1.0
2 NaN
3 NaN
4 NaN
5 NaN
6 NaN
7 NaN
8 NaN
9 NaN
Name: 1, dtype: float64
Pour avoir vraiment l’indexe 0
, nous devons utilisé l’attribut loc
comme suit:
nouveau_df.loc[0]
0 0.0
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
6 NaN
7 NaN
8 NaN
9 NaN
Name: 0, dtype: float64
Nous comprenons bien que les indexes sont des étiquettes fournies à la création du DataFrame
. Ces étiquettes peuvent être modifiés de différentes façons. Voici une manière:
>>> df.index = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
>>> df
0 1 2 3 4 5 6 7 8 9
A 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
B 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
C 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
D 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
E 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
F 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
G 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
H 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
I 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
J 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
Nous venons de modifier les indexes de lignes par des lettres A
jusqu’à J
.
Pour modifier les en-têtes de colonne, nous utilisons plutôt l’attribut columns
comme suit:
>>> df.columns = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
>>> df
A B C D E F G H I J
A 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
B 0 1.0 NaN NaN NaN NaN NaN NaN NaN NaN
C 0 1.0 1.0 NaN NaN NaN NaN NaN NaN NaN
D 0 1.0 1.0 2.0 NaN NaN NaN NaN NaN NaN
E 0 1.0 1.0 2.0 3.0 NaN NaN NaN NaN NaN
F 0 1.0 1.0 2.0 3.0 5.0 NaN NaN NaN NaN
G 0 1.0 1.0 2.0 3.0 5.0 8.0 NaN NaN NaN
H 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 NaN NaN
I 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 NaN
J 0 1.0 1.0 2.0 3.0 5.0 8.0 13.0 21.0 34.0
Par la suite, nous pouvons accéder aux lignes par leur indexe renommé comme par exemple:
>>> df.loc['A']
A 0.0
B NaN
C NaN
D NaN
E NaN
F NaN
G NaN
H NaN
I NaN
J NaN
Name: A, dtype: float64
Nous pouvons accéder à une valeur particulière dans le DataFrame
par un tuple comme par exemple:
>>> df.loc[('A', 'A')]
0
et par la suite, nous pouvons y affecter de nouvelles valeurs comme par exemple:
>>> df.loc[('A', 'A')] = 1
>>> df.loc[('A', 'A')]
1
Pour filtrer les colonnes pour l’ensemble des lignes, nous pouvons écrire par exemple:
>>> df.A
A 1
B 0
C 0
D 0
E 0
F 0
G 0
H 0
I 0
J 0
ou plus explicitement:
>>> df['A']
A 1
B 0
C 0
D 0
E 0
F 0
G 0
H 0
I 0
J 0
Name: A, dtype: int64
et nous pouvons y inclure plusieurs colonnes comme ici:
>>> df[['A','B']]
A B
A 1 NaN
B 0 1.0
C 0 1.0
D 0 1.0
E 0 1.0
F 0 1.0
G 0 1.0
H 0 1.0
I 0 1.0
J 0 1.0