Retour à l'accueil

Première expérimentation avec la librairie Pandas en Python

Publié le

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 loccomme 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