La bibliothèque Pandas est un outil fondamental dans l'écosystème Python pour l'analyse et la manipulation de données. Construite sur NumPy, elle excelle dans le traitement de données textuelles et tabulaires, se positionnant comme le module central pour des tâches telles que l'analyse, le traitement et la visualisation de données.
Pandas offre deux structures de données principales :
- Les Series : similaires aux tableaux unidimensionnels de NumPy, mais avec des étiquettes d'index.
- Les DataFrames : des structures tabulaires bidimensionnelles, comparables à des feuilles de calcul ou des tables de bases de données, composées de collections de Series partageant le même index.
Ses capacités s'étendent à :
- La lecture et l'écriture de données depuis divers formats (CSV, Excel, SQL, JSON, HDF, etc.).
- Des opérations complètes sur des tables uniques : ajout, suppression, modification, interrogation, découpage, application de fonctions d'ordre supérieur, regroupement et agrégation.
- La fusion et la jointure de multiples tables de données.
- Des fonctions de traçage de base pour la visualisation.
- Des outils pour l'analyse statistique élémentaire.
I. La Structure de Données Series
Une Series Pandas est un objet unidimensionnel capable de contenir différents types de données, associé à un index (des étiquettes de données). Elle peut être conceptualisée comme une combinaison d'une liste (ou tableau) et d'un dictionnaire.
import numpy as np
import pandas as pd
# Création d'une Series avec une valeur constante et un index personnalisé
serie_constante = pd.Series(0, index=['pomme', 'banane', 'cerise', 'datte'])
print("Series constante :")
print(serie_constante)
# Résultat :
# pomme 0
# banane 0
# cerise 0
# datte 0
# dtype: int64
print("\nValeurs de la Series :", serie_constante.values)
# [0 0 0 0]
print("Index de la Series :", serie_constante.index)
# Index(['pomme', 'banane', 'cerise', 'datte'], dtype='object')
1.1 Création de Series
Il existe plusieurs manières de construire une Series :
1. À partir d'une simple liste de données :
serie_simple = pd.Series([10, 'texte', 5.25, 70])
print("Series à partir d'une liste :")
print(serie_simple)
# Résultat :
# 0 10
# 1 texte
# 2 5.25
# 3 70
# dtype: object
print("\nIndex :", serie_simple.index)
# RangeIndex(start=0, stop=4, step=1)
print("Valeurs :", serie_simple.values)
# [10 'texte' 5.25 70]
2. Avec un index explicite (étiquettes personnalisées) :
serie_indexee = pd.Series([10, 'texte', 5.25, 70], index=['premiere', 'deuxieme', 'troisieme', 'quatrieme'])
print("Series avec index explicite :")
print(serie_indexee)
print("\nIndex :", serie_indexee.index)
print("Valeurs :", serie_indexee.values)
premiere 10
deuxieme texte
troisieme 5.25
quatrieme 70
dtype: object
Index(['premiere', 'deuxieme', 'troisieme', 'quatrieme'], dtype='object')
[10 'texte' 5.25 70]
3. À l'aide d'un dictionnaire Python :
donnees_villes = {'Paris': 2141000, 'Lyon': 513000, 'Marseille': 861000, 'Toulouse': 479000}
serie_depuis_dict = pd.Series(donnees_villes)
print("Series à partir d'un dictionnaire :")
print(serie_depuis_dict)
Paris 2141000
Lyon 513000
Marseille 861000
Toulouse 479000
dtype: int64
1.2 Compatibilité des Series avec NumPy (accès par position)
Les Series supportent de nombreuses fonctionnalités de NumPy pour l'indexation et les opérations arithmétiques.
| Description |
Méthode / Opération |
| Création depuis un tableau NumPy |
pd.Series(tableau_np) |
| Opérations avec un scalaire |
ma_serie * 2 |
| Opérations entre deux Series |
serie1 + serie2 |
| Indexation par position |
ma_serie[0], ma_serie[[1, 2, 4]] |
| Découpage (slicing) |
ma_serie[0:2] |
| Fonctions universelles NumPy |
np.abs(ma_serie) |
| Filtrage booléen |
ma_serie[ma_serie > 0] |
valeurs_np = np.array([10.0, 20.0, 30.0, 40.0, np.nan])
print("Tableau NumPy :", valeurs_np)
# [10. 20. 30. 40. nan]
serie_numerique = pd.Series(valeurs_np, index=['a', 'b', 'c', 'd', 'e'])
print("\nSeries numérique :")
print(serie_numerique)
# Résultat :
# a 10.0
# b 20.0
# c 30.0
# d 40.0
# e NaN
# dtype: float64
print("\nSeries au carré :")
print(serie_numerique**2)
# Résultat :
# a 100.0
# b 400.0
# c 900.0
# d 1600.0
# e NaN
# dtype: float64
print("\nAccès à l'élément d'index 0 :", serie_numerique[0])
print("Accès par étiquette 'a' :", serie_numerique['a'])
print("\nAccès à plusieurs éléments par position :")
print(serie_numerique[[0, 1, 2]])
# a 10.0
# b 20.0
# c 30.0
# dtype: float64
print("\nDécoupage des éléments (0 à 2, exclusif) :")
print(serie_numerique[0:2])
# a 10.0
# b 20.0
# dtype: float64
print("\nApplication de np.sin sur la Series :")
print(np.sin(serie_numerique))
# a -0.544021
# b 0.912945
# c -0.988032
# d 0.745113
# e NaN
# dtype: float64
print("\nFiltrage des éléments > 15 :")
print(serie_numerique[serie_numerique > 15])
# b 20.0
# c 30.0
# d 40.0
# dtype: float64
1.3 Compatibilité des Series avec les Dictionnaires (accès par étiquette)
Les Series se comportent comme des dictionnaires pour l'accès et la vérification d'existence.
| Description |
Méthode / Opération |
| Création depuis un dictionnaire |
pd.Series(mon_dict) |
| Vérification d'existence de clé |
'cle' in ma_serie |
| Indexation par étiquette |
ma_serie['etiquette'], ma_serie[['etiquette1', 'etiquette2']] |
serie_dict_exemple = pd.Series({'prix_cafe': 2.50, 'prix_the': 2.00})
print("Series dictionnaire :")
print(serie_dict_exemple)
# prix_cafe 2.5
# prix_the 2.0
# dtype: float64
print("\n'prix_cafe' est-il dans la Series ?", 'prix_cafe' in serie_dict_exemple)
# True
print("Valeur pour 'prix_the' :", serie_dict_exemple['prix_the'])
# 2.0
1.4 Gestion des Données Manquantes dans une Series
Pandas offre des méthodes dédiées pour traiter les valeurs manquantes (représentées par np.nan).
| Méthode |
Description |
dropna() |
Supprime les lignes (ou éléments) contenant des valeurs NaN. |
fillna(valeur) |
Remplace les valeurs NaN par la valeur spécifiée. |
isnull() |
Retourne un tableau booléen, True pour les NaN. |
notnull() |
Retourne un tableau booléen, True pour les valeurs non NaN. |
serie_avec_nan = pd.Series([1.0, 2.0, np.nan, 4.0, np.nan], index=['x', 'y', 'z', 'w', 'v'])
print("Series originale avec NaN :")
print(serie_avec_nan)
# x 1.0
# y 2.0
# z NaN
# w 4.0
# v NaN
# dtype: float64
print("\nSeries après dropna() :")
print(serie_avec_nan.dropna())
# x 1.0
# y 2.0
# w 4.0
# dtype: float64
print("\nSeries après fillna(0) :")
print(serie_avec_nan.fillna(0))
# x 1.0
# y 2.0
# z 0.0
# w 4.0
# v 0.0
# dtype: float64
print("\nIndication des valeurs nulles (isnull()) :")
print(serie_avec_nan.isnull())
# x False
# y False
# z True
# w False
# v True
# dtype: bool
print("\nIndication des valeurs non nulles (notnull()) :")
print(serie_avec_nan.notnull())
# x True
# y True
# z False
# w True
# v False
# dtype: bool
II. La Structure de Données DataFrame
Un DataFrame est une structure de données tabulaire bidimensionnelle, organisée en colonnes et en lignes, chacune ayant un index. On peut le voir comme un ensemble de Series qui partagent le même index.
2.1 Génération d'un tableau de dates : date_range
La fonction pd.date_range est utile pour créer des index basés sur des séquences de dates.
| Paramètre |
Description |
start |
Date de début. |
end |
Date de fin. |
periods |
Nombre de périodes à générer. |
freq |
Fréquence des dates (ex: 'D' pour jour, 'M' pour mois, 'H' pour heure, etc.). Par défaut 'D'. |
dates_mensuelles = pd.date_range('2023-01-01', periods=6, freq='M')
print("Index de dates mensuelles :")
print(dates_mensuelles)
# DatetimeIndex(['2023-01-31', '2023-02-28', '2023-03-31', '2023-04-30',
# '2023-05-31', '2023-06-30'],
# dtype='datetime64[ns]', freq='M')
np.random.seed(42) # Pour la reproductibilité
donnees_aleatoires = np.random.randn(6, 4) * 5 # Valeurs aléatoires pour le DataFrame
print("\nMatrice de données aléatoires :")
print(donnees_aleatoires)
# Création du DataFrame
cadre_donnees_principal = pd.DataFrame(donnees_aleatoires, index=dates_mensuelles, columns=['Col_A', 'Col_B', 'Col_C', 'Col_D'])
print("\nDataFrame créé :")
print(cadre_donnees_principal)
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
1.231269 |
1.442845 |
0.867373 |
5.432657 |
| 2023-02-28 |
-0.579477 |
10.749007 |
1.839655 |
-0.082725 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
| 2023-05-31 |
-1.259972 |
-0.547141 |
-0.597992 |
0.639591 |
| 2023-06-30 |
-1.275037 |
0.627918 |
-0.076899 |
-1.579782 |
III. Attributs d'un DataFrame
Les DataFrames disposent de divers attributs pour inspecter leurs caractéristiques.
| Attribut |
Description |
dtypes |
Affiche les types de données de chaque colonne. |
index |
Permet de voir l'index (étiquettes de lignes). |
columns |
Retourne les étiquettes des colonnes. |
values |
Obtient les données du DataFrame sous forme de tableau NumPy (sans les index ni les en-têtes). |
describe() |
Fournit des statistiques descriptives (min, max, moyenne, écart-type, quartiles) pour les colonnes numériques. |
T ou transpose() |
Transposition du DataFrame (échange lignes et colonnes). |
sort_index() |
Trie le DataFrame par ses index (lignes ou colonnes). |
sort_values() |
Trie le DataFrame selon les valeurs d'une ou plusieurs colonnes. |
print("Types de données :")
print(cadre_donnees_principal.dtypes)
# Col_A float64
# Col_B float64
# Col_C float64
# Col_D float64
# dtype: object
print("\nIndex des lignes :")
print(cadre_donnees_principal.index)
# DatetimeIndex(['2023-01-31', '2023-02-28', '2023-03-31', '2023-04-30',
# '2023-05-31', '2023-06-30'],
# dtype='datetime64[ns]', freq='M')
print("\nNoms des colonnes :")
print(cadre_donnees_principal.columns)
# Index(['Col_A', 'Col_B', 'Col_C', 'Col_D'], dtype='object')
print("\nValeurs du DataFrame (tableau NumPy) :")
print(cadre_donnees_principal.values)
print("\nStatistiques descriptives :")
print(cadre_donnees_principal.describe())
|
Col_A |
Col_B |
Col_C |
Col_D |
| count |
6.000000 |
6.000000 |
6.000000 |
6.000000 |
| mean |
0.007801 |
2.287468 |
0.287663 |
0.786066 |
| std |
0.916894 |
3.945890 |
0.741031 |
2.105436 |
| min |
-1.275037 |
-0.547141 |
-0.597992 |
-1.579782 |
| 25% |
-0.989858 |
0.485348 |
-0.230337 |
-0.063421 |
| 50% |
-0.028867 |
0.855220 |
-0.150766 |
0.155288 |
| 75% |
0.642598 |
1.342764 |
0.620268 |
0.558715 |
| max |
1.231269 |
10.749007 |
1.839655 |
5.432657 |
print("\nDataFrame transposé :")
print(cadre_donnees_principal.T)
|
2023-01-31 00:00:00 |
2023-02-28 00:00:00 |
2023-03-31 00:00:00 |
2023-04-30 00:00:00 |
2023-05-31 00:00:00 |
2023-06-30 00:00:00 |
| Col_A |
1.231269 |
-0.579477 |
0.621743 |
0.662883 |
-1.259972 |
-1.275037 |
| Col_B |
1.442845 |
10.749007 |
0.297615 |
1.082522 |
-0.547141 |
0.627918 |
| Col_C |
0.867373 |
1.839655 |
-0.231571 |
-0.224632 |
-0.597992 |
-0.076899 |
| Col_D |
5.432657 |
-0.082725 |
-0.005510 |
0.316086 |
0.639591 |
-1.579782 |
# Trier par index des lignes (par défaut axis=0)
print("\nDataFrame trié par index des lignes :")
print(cadre_donnees_principal.sort_index(axis=0))
# Trier par index des colonnes (axis=1)
print("\nDataFrame trié par index des colonnes :")
print(cadre_donnees_principal.sort_index(axis=1))
# Trier par les valeurs de la colonne 'Col_B'
print("\nDataFrame trié par les valeurs de 'Col_B' :")
print(cadre_donnees_principal.sort_values(by='Col_B'))
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-05-31 |
-1.259972 |
-0.547141 |
-0.597992 |
0.639591 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-06-30 |
-1.275037 |
0.627918 |
-0.076899 |
-1.579782 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
| 2023-01-31 |
1.231269 |
1.442845 |
0.867373 |
5.432657 |
| 2023-02-28 |
-0.579477 |
10.749007 |
1.839655 |
-0.082725 |
IV. Sélection de Données dans un DataFrame
La sélection de données est une opération cruciale. Voici comment y parvenir avec différentes méthodes.
print("DataFrame actuel :")
print(cadre_donnees_principal)
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
1.231269 |
1.442845 |
0.867373 |
5.432657 |
| 2023-02-28 |
-0.579477 |
10.749007 |
1.839655 |
-0.082725 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
| 2023-05-31 |
-1.259972 |
-0.547141 |
-0.597992 |
0.639591 |
| 2023-06-30 |
-1.275037 |
0.627918 |
-0.076899 |
-1.579782 |
4.1 Sélection par noms de colonnes
print("\nSélection de la colonne 'Col_B' :")
print(cadre_donnees_principal['Col_B'])
# 2023-01-31 1.442845
# 2023-02-28 10.749007
# 2023-03-31 0.297615
# 2023-04-30 1.082522
# 2023-05-31 -0.547141
# 2023-06-30 0.627918
# Freq: M, Name: Col_B, dtype: float64
print("\nSélection des colonnes 'Col_A' et 'Col_C' :")
print(cadre_donnees_principal[['Col_A', 'Col_C']])
|
Col_A |
Col_C |
| 2023-01-31 |
1.231269 |
0.867373 |
| 2023-02-28 |
-0.579477 |
1.839655 |
| 2023-03-31 |
0.621743 |
-0.231571 |
| 2023-04-30 |
0.662883 |
-0.224632 |
| 2023-05-31 |
-1.259972 |
-0.597992 |
| 2023-06-30 |
-1.275037 |
-0.076899 |
4.2 Sélection par étiquettes de lignes (loc)
La méthode .loc[] permet d'accéder aux données en utilisant les étiquettes des lignes et des colonnes.
print("\nSélection de lignes par étiquette d'index (plage incluse) :")
print(cadre_donnees_principal.loc['2023-01-31':'2023-03-31'])
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
1.231269 |
1.442845 |
0.867373 |
5.432657 |
| 2023-02-28 |
-0.579477 |
10.749007 |
1.839655 |
-0.082725 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
4.3 Sélection par positions entières (iloc)
La méthode .iloc[] fonctionne de manière similaire à l'indexation de tableaux NumPy, en utilisant des positions entières.
print("\nValeur à la ligne 2, colonne 1 (index 0,1) :", cadre_donnees_principal.iloc[2, 1])
# 0.2976154378730419
print("\nSélection par positions entières (lignes 1 à 3, colonnes 1 à 3) :")
print(cadre_donnees_principal.iloc[1:4, 1:4])
|
Col_B |
Col_C |
Col_D |
| 2023-02-28 |
10.749007 |
1.839655 |
-0.082725 |
| 2023-03-31 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
1.082522 |
-0.224632 |
0.316086 |
4.4 Sélection avec des conditions logiques
print("\nLignes où 'Col_A' est supérieure à 0 :")
print(cadre_donnees_principal[cadre_donnees_principal['Col_A'] > 0])
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
1.231269 |
1.442845 |
0.867373 |
5.432657 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
print("\nLignes où 'Col_A' est supérieure à 0 ET 'Col_B' est inférieure à 2 :")
print(cadre_donnees_principal[(cadre_donnees_principal['Col_A'] > 0) & (cadre_donnees_principal['Col_B'] < 2)])
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
1.231269 |
1.442845 |
0.867373 |
5.432657 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
V. Modification de valeurs dans un DataFrame
Il est simple de modifier les valeurs d'un DataFrame, que ce soit par position, par étiquette, ou par condition.
print("DataFrame avant modification :")
print(cadre_donnees_principal)
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
1.231269 |
1.442845 |
0.867373 |
5.432657 |
| 2023-02-28 |
-0.579477 |
10.749007 |
1.839655 |
-0.082725 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
| 2023-05-31 |
-1.259972 |
-0.547141 |
-0.597992 |
0.639591 |
| 2023-06-30 |
-1.275037 |
0.627918 |
-0.076899 |
-1.579782 |
# Modifier les valeurs des deux premières lignes et colonnes à 0
cadre_donnees_principal.iloc[0:2, 0:2] = 0
print("\nDataFrame après modification des premières cellules :")
print(cadre_donnees_principal)
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
0.000000 |
0.000000 |
0.867373 |
5.432657 |
| 2023-02-28 |
0.000000 |
0.000000 |
1.839655 |
-0.082725 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
| 2023-05-31 |
-1.259972 |
-0.547141 |
-0.597992 |
0.639591 |
| 2023-06-30 |
-1.275037 |
0.627918 |
-0.076899 |
-1.579782 |
# Appliquer une modification conditionnelle à des lignes entières
# Toutes les lignes où 'Col_C' est supérieure à 1 seront remplacées par une valeur unique (-1)
cadre_donnees_principal[cadre_donnees_principal['Col_C'] > 1] = -1
print("\nDataFrame après modification conditionnelle (lignes entières) :")
print(cadre_donnees_principal)
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
0.000000 |
0.000000 |
0.867373 |
5.432657 |
| 2023-02-28 |
-1.000000 |
-1.000000 |
-1.000000 |
-1.000000 |
| 2023-03-31 |
0.621743 |
0.297615 |
-0.231571 |
-0.005510 |
| 2023-04-30 |
0.662883 |
1.082522 |
-0.224632 |
0.316086 |
| 2023-05-31 |
-1.259972 |
-0.547141 |
-0.597992 |
0.639591 |
| 2023-06-30 |
-1.275037 |
0.627918 |
-0.076899 |
-1.579782 |
# Convertir en entier pour l'exemple suivant
cadre_donnees_principal = cadre_donnees_principal.astype(int)
# Remplacer toutes les lignes où 'Col_B' contient -1 par 999
cadre_donnees_principal[cadre_donnees_principal['Col_B'].isin([-1])] = 999
print("\nDataFrame après nouvelle modification conditionnelle :")
print(cadre_donnees_principal)
|
Col_A |
Col_B |
Col_C |
Col_D |
| 2023-01-31 |
0 |
0 |
0 |
5 |
| 2023-02-28 |
999 |
999 |
999 |
999 |
| 2023-03-31 |
0 |
0 |
0 |
0 |
| 2023-04-30 |
0 |
1 |
0 |
0 |
| 2023-05-31 |
-1 |
0 |
0 |
0 |
| 2023-06-30 |
-1 |
0 |
0 |
-1 |
VI. Lecture de fichiers CSV
Les fichiers CSV (Comma Separated Values), TSV (Tab Separated Values) ou TXT sont des formats courants pour les données tabulaires. Pandas facilite leur importation.
| Type de fichier |
Description |
Méthode Pandas |
| CSV, TSV, TXT |
Fichier texte brut avec séparateur (virgule, tabulation, etc.) |
pd.read_csv |
| Excel |
Fichier Microsoft Excel (.xls ou .xlsx) |
pd.read_excel |
| SQL |
Base de données relationnelle |
pd.read_sql |
from io import StringIO
# Exemple de données CSV en chaîne de caractères
donnees_csv_texte = '''val1,val2,val3,val4
1.1,A,true,10
2.2,,false,20
3.3,C,,30
4.4,D,true,
,E,false,50
'''
# Utilisation de StringIO pour simuler un fichier
flux_csv = StringIO(donnees_csv_texte)
df_csv = pd.read_csv(flux_csv)
print("DataFrame lu depuis CSV :")
print(df_csv)
print("\nPremières lignes (head()) :")
print(df_csv.head(2)) # Affiche les 2 premières lignes
print("\nForme du DataFrame (lignes, colonnes) :", df_csv.shape)
print("Noms des colonnes :", df_csv.columns.tolist())
print("Index des lignes :", df_csv.index)
print("Types de données par colonne :")
print(df_csv.dtypes)
|
val1 |
val2 |
val3 |
val4 |
| 0 |
1.1 |
A |
True |
10.0 |
| 1 |
2.2 |
NaN |
False |
20.0 |
| 2 |
3.3 |
C |
NaN |
30.0 |
| 3 |
4.4 |
D |
True |
NaN |
| 4 |
NaN |
E |
False |
50.0 |
VII. Gestion des Données Manquantes
Les valeurs manquantes sont courantes et nécessitent une attention particulière. Pandas propose plusieurs méthodes pour les identifier et les traiter.
print("Matrice booléenne des valeurs nulles :")
print(df_csv.isnull())
|
val1 |
val2 |
val3 |
val4 |
| 0 |
False |
False |
False |
False |
| 1 |
False |
True |
False |
False |
| 2 |
False |
False |
True |
False |
| 3 |
False |
False |
False |
True |
| 4 |
True |
False |
False |
False |
# Compter le nombre de valeurs nulles par colonne
print("\nNombre de valeurs nulles par colonne :")
print(df_csv.isnull().sum())
# val1 1
# val2 1
# val3 1
# val4 1
# dtype: int64
# Supprimer les lignes contenant au moins une valeur NaN (axis=0 par défaut)
print("\nDataFrame après suppression des lignes avec NaN :")
print(df_csv.dropna(axis=0))
# Supprimer les colonnes contenant au moins une valeur NaN (axis=1)
print("\nDataFrame après suppression des colonnes avec NaN :")
print(df_csv.dropna(axis=1))
# Supprimer les lignes où TOUTES les valeurs sont NaN
# (Dans cet exemple, il n'y en a pas, donc le DataFrame reste inchangé)
print("\nDataFrame après suppression des lignes entièrement NaN (how='all') :")
print(df_csv.dropna(how='all'))
# Supprimer les lignes qui n'ont pas au moins 3 valeurs non-NaN
print("\nDataFrame après suppression des lignes avec moins de 3 valeurs valides (thresh=3) :")
print(df_csv.dropna(thresh=3))
# Supprimer les lignes où 'val2' est NaN
print("\nDataFrame après suppression des lignes avec NaN dans 'val2' :")
print(df_csv.dropna(subset=['val2']))
# Remplir toutes les valeurs NaN avec une valeur spécifique (ex: 'MANQUANT')
print("\nDataFrame après remplacement des NaN par 'MANQUANT' :")
print(df_csv.fillna(value='MANQUANT'))
VIII. Fusion de Données
Pandas offre des fonctions robustes pour combiner des DataFrames. La fonction pd.concat est la plus flexible.
df_zeros = pd.DataFrame(np.zeros((2, 3)), columns=['X', 'Y', 'Z'])
print("DataFrame 'zeros' :")
print(df_zeros)
# X Y Z
# 0 0.0 0.0 0.0
# 1 0.0 0.0 0.0
df_ones = pd.DataFrame(np.ones((2, 3)), columns=['X', 'Y', 'Z'])
print("\nDataFrame 'ones' :")
print(df_ones)
# X Y Z
# 0 1.0 1.0 1.0
# 1 1.0 1.0 1.0
# Concaténation par ligne (ajout des lignes de df_ones sous df_zeros, axis=0 par défaut)
print("\nConcaténation par ligne :")
print(pd.concat([df_zeros, df_ones], axis=0))
# X Y Z
# 0 0.0 0.0 0.0
# 1 0.0 0.0 0.0
# 0 1.0 1.0 1.0
# 1 1.0 1.0 1.0
# Concaténation par colonne (ajout des colonnes de df_ones à droite de df_zeros)
print("\nConcaténation par colonne :")
print(pd.concat([df_zeros, df_ones], axis=1))
# X Y Z X Y Z
# 0 0.0 0.0 0.0 1.0 1.0 1.0
# 1 0.0 0.0 0.0 1.0 1.0 1.0
# La méthode .append() est une ancienne façon de concaténer par ligne.
# Elle est dépréciée depuis Pandas 1.4.0 et sera retirée dans une future version.
# Il est recommandé d'utiliser pd.concat() à la place.
print("\nUtilisation de .append() (dépréciée, utilisez pd.concat) :")
print(df_zeros._append(df_ones, ignore_index=True)) # ignore_index=True pour réinitialiser l'index
# X Y Z
# 0 0.0 0.0 0.0
# 1 0.0 0.0 0.0
# 2 1.0 1.0 1.0
# 3 1.0 1.0 1.0
IX. Importation et Exportation de Données
Pandas simplifie les opérations d'entrée/sortie de données avec des fonctions read_* et to_*.
9.1 Lecture de fichiers (Importation)
Les fonctions de lecture comme pd.read_csv() ou pd.read_excel() acceptent de nombreux paramètres pour personnaliser l'importation.
| Paramètre |
Description |
sep |
Caractère séparateur (ex: ',', '\t'). Peut être une expression régulière comme '\s+'. |
header=None |
Indique que le fichier n'a pas d'en-tête de colonne. |
names |
Liste des noms de colonnes à attribuer. |
index_col |
Spécifie quelle colonne doit être utilisée comme index du DataFrame. |
skiprows |
Liste des numéros de lignes à ignorer au début du fichier. |
na_values |
Liste de chaînes de caractères à interpréter comme des valeurs manquantes (NaN). |
parse_dates |
Booléen ou liste de colonnes à analyser comme des dates. |
# Exemple générique de lecture
# df_import = pd.read_excel("mon_fichier.xlsx")
# df_import = pd.read_csv("mes_donnees.csv", sep=';', header=0)
9.2 Écriture de fichiers (Exportation)
Les méthodes to_csv(), to_excel(), etc., permettent d'exporter des DataFrames.
| Paramètre |
Description |
sep |
Séparateur de champs pour les fichiers texte. |
na_rep |
Chaîne de caractères utilisée pour représenter les valeurs NaN (par défaut vide). |
header=False |
N'écrit pas les noms de colonnes dans le fichier. |
index=False |
N'écrit pas l'index des lignes dans le fichier. |
columns |
Liste des colonnes à inclure dans l'exportation. |
# Exemple générique d'écriture
# df_export.to_excel("resultats.xlsx", index=False)
# df_export.to_csv("rapport.csv", sep=',', na_rep='N/A')
X. Lecture de fichiers JSON avec Pandas
Pandas peut directement lire des chaînes JSON ou des fichiers JSON et les convertir en DataFrame, grâce à la fonction pd.read_json().
json_data_str = '''
[
{"jeu":"loto","numero_tirage":"20230101-100","resultat":"1,5,9,12,18","id_unique":"ABC12345","extra_info":null,"timestamp":1672531200000},
{"jeu":"loto","numero_tirage":"20230101-101","resultat":"2,6,10,15,20","id_unique":"DEF67890","extra_info":null,"timestamp":1672534800000},
{"jeu":"kino","numero_tirage":"20230101-102","resultat":"3,7,11,14,22","id_unique":"GHI11223","extra_info":null,"timestamp":1672538400000}
]
'''
df_json_loto = pd.read_json(json_data_str, orient='records')
print("DataFrame lu depuis JSON ('records') :")
print(df_json_loto)
# Exportation vers un fichier Excel
# df_json_loto.to_excel('resultats_json.xlsx',
# index=False,
# columns=["jeu", "numero_tirage", "resultat", "id_unique", "extra_info", "timestamp"])
|
jeu |
numero_tirage |
resultat |
id_unique |
extra_info |
timestamp |
| 0 |
loto |
20230101-100 |
1,5,9,12,18 |
ABC12345 |
None |
1672531200000 |
| 1 |
loto |
20230101-101 |
2,6,10,15,20 |
DEF67890 |
None |
1672534800000 |
| 2 |
kino |
20230101-102 |
3,7,11,14,22 |
GHI11223 |
None |
1672538400000 |
10.1 Les cinq formes du paramètre orient
Le paramètre orient spécifie le format attendu de la chaîne JSON. Il peut prendre l'une des cinq valeurs suivantes :
1. 'split' : format dictionnaire {index -> [index], columns -> [columns], data -> [values]}
Ce format contient explicitement les listes d'index, de colonnes et les données matricielles. Les clés doivent être exactement 'index', 'columns' et 'data'.
json_split_str = '{"index":[10,20,30],"columns":["alpha","beta"],"data":[[100,101],[102,103],[104,105]]}'
df_split = pd.read_json(json_split_str, orient='split')
print("DataFrame avec orient='split' :")
print(df_split)
|
alpha |
beta |
| 10 |
100 |
101 |
| 20 |
102 |
103 |
| 30 |
104 |
105 |
2. 'records' : format liste de dictionnaires [{column -> value}, ...]
Il s'agit d'une liste où chaque élément est un dictionnaire représentant une ligne du DataFrame, avec les noms de colonnes comme clés et les valeurs correspondantes.
json_records_str = '''
[
{"id_produit":1, "nom":"Clavier", "prix":75.0},
{"id_produit":2, "nom":"Souris", "prix":25.0}
]
'''
df_records = pd.read_json(json_records_str, orient='records')
print("\nDataFrame avec orient='records' :")
print(df_records)
|
id_produit |
nom |
prix |
| 0 |
1 |
Clavier |
75.0 |
| 1 |
2 |
Souris |
25.0 |
3. 'index' : format dictionnaire {index -> {column -> value}}
Les clés du dictionnaire externe sont les index, et leurs valeurs sont des dictionnaires représentant les lignes (clé: colonne, valeur: donnée).
json_index_str = '{"ID001":{"nom":"Alice","age":30},"ID002":{"nom":"Bob","age":24}}'
df_index = pd.read_json(json_index_str, orient='index')
print("\nDataFrame avec orient='index' :")
print(df_index)
|
nom |
age |
| ID001 |
Alice |
30 |
| ID002 |
Bob |
Bob |
4. 'columns' : format dictionnaire {column -> {index -> value}}
Les clés du dictionnaire externe sont les noms de colonnes, et leurs valeurs sont des dictionnaires représentant les colonnes (clé: index, valeur: donnée).
json_columns_str = '{"nom":{"R1":"Charlie","R2":"Diana"},"ville":{"R1":"Londres","R2":"Paris"}}'
df_columns = pd.read_json(json_columns_str, orient='columns')
print("\nDataFrame avec orient='columns' :")
print(df_columns)
|
nom |
ville |
| R1 |
Charlie |
Londres |
| R2 |
Diana |
Paris |
5. 'values' : simplement le tableau de valeurs
C'est une liste de listes, représentant directement les valeurs du DataFrame sans informations d'index ou de colonnes explicites.
json_values_str = '[["fruit","pomme"],["couleur","rouge"]]'
df_values = pd.read_json(json_values_str, orient='values')
print("\nDataFrame avec orient='values' :")
print(df_values)
|
0 |
1 |
| 0 |
fruit |
pomme |
| 1 |
couleur |
rouge |
XI. Lecture de requêtes SQL avec Pandas
Pandas peut se connecter à des bases de données SQL et exécuter des requêtes pour importer les résultats directement dans un DataFrame via pd.read_sql().
import pymysql # Nécessite 'pip install pymysql'
# Fonction pour se connecter à la base de données et exécuter une requête SQL
def executer_requete_sql(requete):
connexion = None # Initialiser connexion à None
try:
# Configuration de la connexion à MySQL
connexion = pymysql.connect(
host="localhost",
port=3306,
user="root",
password="mysecretpassword", # Utilisez un mot de passe sécurisé
db="ma_base_donnees",
charset='utf8mb4', # Assurez-vous d'avoir le bon encodage
cursorclass=pymysql.cursors.DictCursor
)
# Lire les données de la base de données directement dans un DataFrame
data_frame_sql = pd.read_sql(requete, con=connexion)
return data_frame_sql
except Exception as e:
print(f"Erreur lors de l'exécution de la requête SQL : {e}")
return pd.DataFrame() # Retourne un DataFrame vide en cas d'erreur
finally:
if connexion:
connexion.close() # S'assurer que la connexion est toujours fermée
# Exemple d'utilisation
requete_sql_exemple = "SELECT id, nom, email FROM utilisateurs LIMIT 5" # Votre requête SQL
resultats_db = executer_requete_sql(requete_sql_exemple)
if not resultats_db.empty:
print("\nNoms des colonnes de la table :", resultats_db.columns.tolist())
print("\nDonnées lues depuis SQL :")
print(resultats_db)
else:
print("\nAucune donnée récupérée ou une erreur s'est produite.")