đŒ Pandas
- Intro
- Explorer
- Filtrer / Trier
- Sélectionner
- Parcourir
- Nettoyer
- Transformer
- Statistiques
- Exporter
- Visualiser
- Activités
Ă la rencontre 10, nous avons appris Ă utiliser NumPy faire des calculs sur des tableaux de nombres. NumPy est puissant, mais il a une limite : il travaille sur des donnĂ©es dâun seul type (tous des nombres, ou tous des textes). Dans la rĂ©alitĂ©, un jeu de donnĂ©es scientifiques contient souvent des colonnes de types diffĂ©rents : des mesures numĂ©riques, des dates, des catĂ©gories, des noms. Pour manipuler ce genre de donnĂ©es, NumPy seul devient vite insuffisant :
import numpy as np
# Avec NumPy : difficile de mélanger des types
patient_ids = np.array(["P001", "P002", "P003", "P004"])
ages = np.array([34, 58, 45, 27])
glycemies = np.array([5.2, 7.8, 6.1, 4.9])
diagnostics = np.array(["normal", "diabete", "pre_diabete", "normal"])
# Pour filtrer les patients avec une glycémie élevée, il faut jongler entre 4 tableaux séparés...
masque = glycemies > 6.0
print(patient_ids[masque]) # ["P002" "P003"]
print(diagnostics[masque]) # ["diabete" "pre_diabete"]
Câest lĂ quâintervient đŒ Pandas : il regroupe toutes ces colonnes dans un seul objet, le DataFrame, et offre des outils pour les manipuler facilement.
Pour le TP2, vous devrez manipuler des donnĂ©es rĂ©elles. Voici les Ă©tapes typiques dâun pipeline dâanalyse, et les onglets qui y correspondent :
| Ătape | Ce quâon fait | Onglet |
|---|---|---|
| đ„ Charger | Importer un fichier CSV dans un DataFrame | Explorer |
| đ Filtrer | Filtrer et trier les donnĂ©es | Filtrer / Trier |
| đŻ SĂ©lectionner | Choisir des colonnes ou des lignes | SĂ©lectionner |
| đ Parcourir | ItĂ©rer sur les lignes ou colonnes | Parcourir |
| đ§č Nettoyer | GĂ©rer les valeurs manquantes et les doublons | Nettoyer |
| 𧟠Transformer | Créer de nouvelles colonnes | Transformer |
| đ Analyser | Calculer des statistiques, regrouper | Statistiques |
| đ€ Exporter | Enregistrer un DataFrame dans un fichier CSV | Exporter |
| đ Visualiser | Tracer des graphiques | Visualiser |
Pandas nâest quâune des bibliothĂšques utilisĂ©es en science des donnĂ©es.
Pour votre culture gĂ©nĂ©rale, voici lâĂ©cosystĂšme Python dans ce domaine :
- đŒ Pandas : manipulation de donnĂ©es tabulaires (câest le sujet de cette rencontre)
- đš Matplotlib : visualisation de donnĂ©es (on la connait dĂ©jĂ )
- đą NumPy : calcul scientifique sur des tableaux (vue Ă la rencontre 10)
- đ€ Scikit-learn : apprentissage automatique (prochain cours)
- đ§ Keras / TensorFlow : apprentissage profond (deep learning) (cours ultĂ©rieurs)
Les explications de cette section étaient-elles claires ?
On connait dĂ©jĂ les dictionnaires et les listes en Python. Un DataFrame Pandas, c'est exactement ça : un dictionnaire dont les valeurs sont des listes de mĂȘme longueur.
import pandas as pd
data = {
"patient_id": ["P001", "P002", "P003", "P004" ],
"age": [34, 58, 45, 27 ],
"glycemie_mmol_L": [5.2, 7.8, 6.1, 4.9 ],
"tension_systolique": [118, 142, 135, 112 ],
"diagnostic": ["normal", "diabete", "pre_diabete", "normal"],
}
df = pd.DataFrame(data)
print(df)
patient_id age glycemie_mmol_L tension_systolique diagnostic
0 P001 34 5.2 118 normal
1 P002 58 7.8 142 diabete
2 P003 45 6.1 135 pre_diabete
3 P004 27 4.9 112 normal
Quelques points importants Ă observer :
- Les clés du dictionnaire deviennent les noms des colonnes.
- Chaque liste devient une colonne de données.
- La colonne
0, 1, 2, 3à gauche est l'index (numéro de ligne automatique). - Chaque ligne est un enregistrement (ici, un patient).
dfest juste le nom de la variable qui stocke le DataFrame : on aurait pu l'appelerpatientsouplantesou n'importe quoi d'autre.
Un DataFrame peut avoir des milliers de lignes : c'est lĂ que Pandas devient indispensable, lĂ oĂč manipuler des listes et des dictionnaires Ă la main devient ingĂ©rable.
Sous le capot, chaque colonne d'un DataFrame est stockĂ©e comme un tableau NumPy (ndarray). C'est pour ça que Pandas hĂ©rite de la mĂȘme rapiditĂ© de calcul que NumPy, et que des opĂ©rations comme df["col"] * 2 fonctionnent sans boucle, exactement comme tableau * 2 en NumPy.
Dans l'exemple prĂ©cĂ©dent, les donnĂ©es Ă©taient Ă©crites directement dans le code. En pratique, les donnĂ©es proviennent presque toujours de fichiers externes : bases de donnĂ©es, exports Excel, JSON⊠Le format le plus courant est le CSV (Comma-Separated Values) : un simple fichier texte oĂč chaque ligne est un enregistrement et chaque valeur est sĂ©parĂ©e par un dĂ©limiteur (souvent une virgule).
Pandas permet de charger un fichier CSV en une seule ligne avec pd.read_csv(), qui retourne directement un DataFrame prĂȘt Ă ĂȘtre explorĂ©.
Le fichier tips_dataset.csv regroupe des données collectées dans un restaurant : pour chaque repas, on y retrouve le montant de la facture, le pourboire laissé, le jour, le moment de la journée, la taille du groupe, et quelques informations sur le serveur.
Téléchargez-le, placez-le à la racine d'un projet PyCharm, puis chargez-le :
import pandas as pd
df = pd.read_csv('tips_dataset.csv') # â retourne un DataFrame
Ces donnĂ©es serviront Ă illustrer toutes les opĂ©rations qui suivent! đŻ
df.head() retourne les 5 premiÚres lignes par défaut. On peut passer un nombre en argument pour en voir plus.
print(df.head()) # â les 5 premiĂšres lignes
print(df.head(20)) # â les 20 premiĂšres lignes
Résultat :
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4
Si un DataFrame a trop de colonnes ou du contenu trop long, certaines colonnes peuvent ĂȘtre remplacĂ©es par des ....
Dans ce cas, on peut ajouter ces 2 instructions juste aprĂšs les importations en haut du script :
import pandas as pd
pd.set_option('display.max_colwidth', None)
pd.set_option('display.expand_frame_repr', False)
df.shape retourne un tuple (nombre de lignes, nombre de colonnes).
C'est la façon la plus rapide de connaßtre la taille d'un DataFrame.
print(df.shape) # â (244, 7)
print(df.shape[0]) # â 244 (nombre de lignes)
print(df.shape[1]) # â 7 (nombre de colonnes)
len(df) est une alternative Ă df.shape[0] pour obtenir uniquement le nombre de lignes.
print(len(df)) # â 244
print(df.shape[0]) # â 244 (mĂȘme rĂ©sultat)
df.columns retourne les noms des colonnes. On appelle .tolist() pour obtenir une liste Python ordinaire.
print(df.columns.tolist()) # â ['total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size']
Dans un DataFrame, chaque colonne a un type de donnĂ©es (Dtype). On a dĂ©jĂ rencontrĂ© ce concept en NumPy avec tableau.dtype : c'est exactement la mĂȘme notion, appliquĂ©e Ă une colonne. Voici les types les plus courants et leur Ă©quivalent Python :
| Dtype Pandas | Ăquivalent Python | Description |
|---|---|---|
| int64 | int | Nombre entier |
| float64 | float | Nombre décimal |
| object | str | Texte (chaĂźne de caractĂšres) |
| bool | bool | Valeur booléenne (True / False) |
df.info() affiche le nombre de lignes, le nom et le Dtype de chaque colonne, et le nombre de valeurs non-nulles.
C'est souvent la premiÚre chose à appeler pour détecter des colonnes mal typées ou des valeurs manquantes.
df.info() # affiche directement â pas besoin de print()
Résultat :
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 244 entries, 0 to 243
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 total_bill 244 non-null float64
1 tip 244 non-null float64
2 sex 244 non-null object
3 smoker 244 non-null object
4 day 244 non-null object
5 time 244 non-null object
6 size 244 non-null int64
dtypes: float64(2), int64(1), object(3)
memory usage: 13.5+ KB
- RangeIndex: 244 entries â 244 lignes, indexĂ©es de 0 Ă 243
- float64 â nombre dĂ©cimal, aucune valeur manquante (244 non-null)
- object â texte (str en Python)
- int64 â nombre entier
- dtypes: float64(2), int64(1), object(3) â rĂ©sumĂ© des types prĂ©sents dans le DataFrame
df.describe() retourne un résumé statistique rapide pour toutes les colonnes numériques.
print(df.describe())
Résultat :
total_bill tip size
count 244.000000 244.000000 244.000000
mean 19.785943 2.998279 2.569672
std 8.902412 1.383638 0.951100
min 3.070000 1.000000 1.000000
25% 13.347500 2.000000 2.000000
50% 17.795000 2.900000 2.000000
75% 24.127500 3.562500 3.000000
max 50.810000 10.000000 6.000000
- count â nombre de valeurs non-nulles
- mean â moyenne
- std â Ă©cart-type (mesure la dispersion des valeurs)
- min / max â valeur minimale et maximale
- 25% / 50% / 75% â quartiles (50% = mĂ©diane)
Avant d'écrire du code, on peut explorer un fichier CSV directement dans PyCharm en faisant un double-clic dessus. Deux modes sont disponibles en bas de l'éditeur : Mode Text (contenu brut) et Mode Data (tableau interactif avec filtre, tri et recherche).

Mode Text - affichage brut du fichier

Mode Data - affichage tabulaire interactif
â ïž PyCharm (comme Excel, limitĂ© Ă ~1 million de lignes) n'affiche pas nĂ©cessairement toutes les lignes pour des raisons de performance. C'est prĂ©cisĂ©ment pourquoi Pandas est indispensable : il peut traiter des fichiers de plusieurs millions de lignes sans limitation.
| Opération | Syntaxe | Description |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Charger un CSV | df = pd.read_csv('fichier.csv') | Retourne un DataFrame |
| Aperçu des données | df_apercu = df.head(5) | Retourne les 5 premiÚres lignes |
| Dimensions | dimensions = df.shape | Retourne (244, 7) : lignes, colonnes |
| Nombre de lignes | n = len(df) | Retourne le nombre de lignes |
| Noms des colonnes | colonnes = df.columns.tolist() | Retourne une liste des noms de colonnes |
| Types et valeurs manquantes | df.info() | Affiche directement dans la console |
| Statistiques descriptives | df_stats = df.describe() | Retourne un DataFrame (colonnes numériques) |
Les explications de cette section étaient-elles claires ?
Filtrer un DataFrame, c'est ne garder que les lignes qui satisfont une condition, comme un tamis qui laisse passer certaines données et en retient d'autres.
Par exemple, sur un DataFrame de 244 repas dans un restaurant, on pourrait vouloir garder seulement :
- les repas oĂč le pourboire laissĂ© dĂ©passe 5 $
- les repas du dimanche soir
- les repas avec un groupe de plus de 4 personnes
Le résultat est toujours un nouveau DataFrame. Le DataFrame original df n'est pas modifié, et c'est pourquoi on va généralement stocker le résultat dans une nouvelle variable :
df_gros_pourboires = df[df["tip"] > 5]
Quand on écrit df[df["tip"] > 5], Pandas effectue deux étapes :
df["tip"] > 5produit une sĂ©rie de boolĂ©ens :Truepour chaque ligne oĂč le pourboire dĂ©passe 5,Falsesinondf[...]ne conserve que les lignes oĂč la valeur estTrue
C'est exactement la mĂȘme logique que les masques boolĂ©ens vus Ă la rencontre 10 : t[t > 5] en NumPy et df[df["tip"] > 5] en Pandas utilisent le mĂȘme mĂ©canisme. La seule diffĂ©rence : NumPy filtre des valeurs dans un tableau, Pandas filtre des lignes dans un DataFrame.
Par exemple, on pourrait trÚs bien d'abord créer le masque booléen, puis ensuite l'appliquer :
masque = df["tip"] > 5
df_gros_pourboires = df[masque]
Mais en général, on combine les deux étapes en une seule ligne pour plus de concision :
df_gros_pourboires = df[df["tip"] > 5]
print(df_gros_pourboires)
Résultat :
total_bill tip sex smoker day time size
23 39.42 7.58 Male No Sat Dinner 4
44 30.40 5.60 Male No Sun Dinner 4
47 32.40 6.00 Male No Sun Dinner 4
52 34.81 5.20 Female No Sun Dinner 4
59 48.27 6.73 Male No Sat Dinner 4
...
Un filtre simple compare les valeurs d'une colonne à une valeur de référence. On peut utiliser les opérateurs de comparaison habituels.
# Comparaison numérique
df_gros_pourboires = df[df["tip"] > 5] # pourboire supérieur à 5 $
df_petites_tables = df[df["size"] <= 2] # tables de 1 ou 2 personnes
df_facture_exacte = df[df["total_bill"] == 16.99] # montant exact
# Comparaison sur du texte (égalité exacte)
df_souper = df[df["time"] == "Dinner"] # repas du soir seulement
df_non_fumeurs = df[df["smoker"] == "No"] # tables non-fumeurs
df_samedi = df[df["day"] == "Sat"] # repas du samedi
Pour filtrer sur le contenu d'une colonne textuelle, Pandas offre des méthodes .str..
Elles sont utiles quand on veut chercher une sous-chaßne plutÎt que vérifier une égalité exacte.
df_jours_th = df[df["day"].str.contains("Th")] # "Thur" contient "Th"
df_jours_longs = df[df["day"].str.len() > 3] # "Thur" a 4 caractĂšres, "Fri" en a 3
df_majuscule_f = df[df["sex"].str.startswith("F")] # "Female" commence par "F"
On peut combiner plusieurs conditions avec & (ET) et | (OU). Chaque condition doit ĂȘtre entre parenthĂšses (comme avec NumPy).
# & : les deux conditions doivent ĂȘtre vraies
df_dimanche_souper = df[(df["day"] == "Sun") & (df["time"] == "Dinner")]
df_fumeurs_genereux = df[(df["smoker"] == "Yes") & (df["tip"] > 4)]
# | : au moins une des conditions doit ĂȘtre vraie
df_extremes_facture = df[(df["total_bill"] < 5) | (df["total_bill"] > 45)]
df_repas_courts = df[(df["time"] == "Lunch") | (df["size"] == 1)]
Sans parenthĂšses autour de chaque condition, Python interprĂšte mal l'expression et gĂ©nĂšre une erreur. Ăcris toujours (cond1) & (cond2), jamais cond1 & cond2. C'est la mĂȘme rĂšgle que pour les masques boolĂ©ens en NumPy : les parenthĂšses sont nĂ©cessaires lorsque plusieurs conditions sont combinĂ©es.
Quand on veut filtrer sur plusieurs valeurs d'une mĂȘme colonne, isin() est plus lisible qu'une suite de |.
# Garder seulement les repas du jeudi et du vendredi
df_jours_semaine = df[df["day"].isin(["Thur", "Fri"])]
# Garder seulement les grandes tables (4, 5 ou 6 personnes)
df_grandes_tables = df[df["size"].isin([4, 5, 6])]
isin() vs |df[df["day"].isin(["Thur", "Fri"])] est équivalent à df[(df["day"] == "Thur") | (df["day"] == "Fri")], mais beaucoup plus lisible quand la liste grandit.
Trier un DataFrame, c'est réordonner ses lignes selon les valeurs d'une ou plusieurs colonnes.
Par défaut, Pandas trie en ordre croissant (du plus petit au plus grand, ou de A à Z). On peut inverser cet ordre avec ascending=False.
sort_values() retourne un nouveau DataFrame trié. Le DataFrame original n'est pas modifié.
df_trie1 = df.sort_values(by="total_bill") # â ordre croissant par dĂ©faut
df_trie2 = df.sort_values(by="tip", ascending=False) # â ordre dĂ©croissant
df_trie3 = df.sort_values(by=["day", "total_bill"]) # â tri sur 2 colonnes
On peut chaĂźner un filtre et un tri en une seule instruction. Les deux versions ci-dessous produisent exactement le mĂȘme rĂ©sultat :
# Version détaillée : plus facile à lire et à déboguer
df_version1 = df[df["day"].isin(["Sun", "Sat"])]
df_version1 = df_version1.sort_values(by="total_bill")
# Version compacte ("Method Chaining") : une seule ligne
df_version2 = df[df["day"].isin(["Sun", "Sat"])].sort_values(by="total_bill")
Les deux contiennent les repas de fin de semaine, triés par montant de facture.
Plus tÎt on réduit la taille du jeu de données, plus les opérations suivantes sont rapides. Commencez toujours par filtrer avant de trier.
Quand on combine plusieurs opĂ©rations, il peut ĂȘtre difficile d'identifier la source d'une erreur. Le dĂ©bogage est souvent plus simple en dĂ©composant les instructions sur des lignes distinctes : cela permet de vĂ©rifier l'Ă©tat du DataFrame aprĂšs chaque transformation.
En mode débogage, PyCharm offre une fonctionnalité trÚs pratique : le lien "View as DataFrame", visible dans le panneau des variables. Il permet d'inspecter visuellement le contenu d'un DataFrame sous forme de tableau interactif, directement depuis le débogueur.

đ Cliquez sur "View as DataFrame" dans le panneau des variables pour inspecter un DataFrame en cours d'exĂ©cution.

đ Le contenu du DataFrame s'affiche dans une vue tabulaire claire, avec toutes ses lignes et colonnes.
| Opération | Syntaxe | Description |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Filtre simple (nombre) | df_filtrer = df[df["tip"] > 5] | Pourboire supérieur à 5 $ |
| Filtre simple (texte) | df_filtrer = df[df["time"] == "Dinner"] | ĂgalitĂ© exacte sur une colonne texte |
| Filtre texte (.str.) | df_filtrer = df[df["day"].str.contains("Th")] | Colonne contient une sous-chaĂźne |
| Filtre ET | df_filtrer = df[(df["day"] == "Sun") & (df["time"] == "Dinner")] | Les deux conditions vraies |
| Filtre OU | df_filtrer = df[(df["size"] == 1) | (df["size"] == 2)] | Au moins une condition vraie |
| Filtre liste | df_filtrer = df[df["day"].isin(["Thur", "Fri"])] | Valeur parmi une liste |
| Trier croissant | df_trier = df.sort_values(by="tip") | Du plus petit au plus grand |
| Trier décroissant | df_trier = df.sort_values(by="tip", ascending=False) | Du plus grand au plus petit |
| Trier multi-colonnes | df_trier = df.sort_values(by=["day", "tip"]) | Tri sur plusieurs colonnes |
| ChaĂźner filtre + tri | df_resultat = df[df["day"] == "Sun"].sort_values(by="tip") | Filtrer puis trier en une ligne |
Les explications de cette section étaient-elles claires ?
SĂ©lectionner, câest extraire une partie dâun DataFrame : certaines colonnes, certaines lignes, ou une cellule prĂ©cise. Câest diffĂ©rent de filtrer : filtrer choisit des lignes selon une condition, sĂ©lectionner choisit quelles colonnes ou positions on veut voir.
Selon ce quâon sĂ©lectionne, Pandas retourne lâun de ces trois types :
- DataFrame : un tableau Ă deux dimensions, comme
dflui-mĂȘme - Series : une seule colonne ou une seule ligne, câest-Ă -dire une liste de valeurs avec un index
- valeur scalaire : une seule valeur, comme un
intou unfloat
Le type retourné dépend aussi des crochets utilisés :
| Ce quâon sĂ©lectionne | Syntaxe | Type retournĂ© |
|---|---|---|
| Plusieurs colonnes | df[["col1", "col2"]] | DataFrame |
| Une seule colonne | df["col"] | Series |
| Une seule colonne (format tableau) | df[["col"]] | DataFrame |
| Plusieurs lignes (par position) | df.iloc[2:5] | DataFrame |
| Une seule ligne (par position) | df.iloc[3] | Series |
| Une cellule (par position) | df.iat[3, 0] | valeur scalaire (float, string, etc.) |
| Une cellule (par étiquette) | df.at[3, "tip"] | valeur scalaire (float, string, etc.) |
Lorsqu'on sélectionne une seule colonne d'un DataFrame, le résultat est une Series.
Lorsqu'on sélectionne une seule ligne, le résultat est aussi une Series.
Une Series ressemble Ă un dictionnaire parce quâelle associe une Ă©tiquette dâindex Ă chaque valeur :
- Dans une colonne, lâindex correspond aux lignes du DataFrame.
- Dans une ligne, lâindex correspond aux colonnes du DataFrame.
Mais une Series ressemble aussi Ă un tableau NumPy, parce quâon peut faire des opĂ©rations sur toutes ses valeurs dâun coup :
df["tip"] * 2
On peut donc voir une Series comme une colonne ou une ligne de données avec un index.
Câest un objet propre Ă Pandas, qui combine certaines idĂ©es du dictionnaire et du tableau numĂ©rique.
Pour extraire une ou plusieurs colonnes d'un DataFrame, on utilise les crochets []. Le type retourné dépend du nombre de crochets utilisés.
Plusieurs colonnes â DataFrame (doubles crochets)
df_apercu = df[["total_bill", "tip", "day"]] # on donne une liste de colonnes â ["total_bill", "tip", "day"]
print(df_apercu.head(3))
Résultat :
total_bill tip day
0 16.99 1.01 Sun
1 10.34 1.66 Sun
2 21.01 3.50 Sun
Une seule colonne â Series (crochets simples)
serie_tip = df["tip"] # on donne un seul nom de colonne (pas une liste) â "tip"
print(serie_tip.head(3))
Résultat :
0 1.01
1 1.66
2 3.50
Name: tip, dtype: float64
Une seule colonne â DataFrame (doubles crochets)
df_tip = df[["tip"]] # on donne une liste qui contient un seul nom de colonne â ["tip"]
print(df_tip.head(3))
Résultat :
tip
0 1.01
1 1.66
2 3.50
df["tip"] retourne une Series (une dimension).
df[["tip"]] retourne un DataFrame (deux dimensions).
En cas de doute, utilise print(type(...)) pour vérifier.
print(type(df["tip"])) # <class âpandas.core.series.Seriesâ>
print(type(df[["tip"]])) # <class âpandas.core.frame.DataFrameâ>
iloc sélectionne des lignes par position numérique, exactement comme le slicing de liste.
# Plusieurs lignes â DataFrame
df_debut = df.iloc[0:3]
print(df_debut)
Résultat :
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
On peut aussi sélectionner des lignes spécifiques par leur position :
df.iloc[[0, 5, 10]] # â DataFrame â lignes 0, 5 et 10 prĂ©cisĂ©ment - liste de lignes â [0, 5, 10]
df.iloc[[3]] # â DataFrame â une seule ligne (doubles crochets) - liste d'une ligne â [3]
df.iloc[3] # â Series â une seule ligne (crochets simples) - ligne seule â 3
Pour accéder à une seule valeur, df.iat[] (par position) et df.at[] (par étiquette) sont les méthodes recommandées.
# Par position : df.iat[numéro_ligne, numéro_colonne]
valeur = df.iat[0, 1] # ligne 0, colonne 1 â tip = 1.01
# Par étiquette : df.at[index, nom_colonne]
valeur = df.at[0, "tip"] # ligne dâindex 0, colonne "tip" â 1.01
loc sĂ©lectionne par Ă©tiquette de ligne. Dans un DataFrame normal les Ă©tiquettes sont numĂ©riques (0, 1, 2, ...), donc loc et iloc donnent le mĂȘme rĂ©sultat. loc devient indispensable quand les lignes ont des Ă©tiquettes textuelles, comme avec df.describe() :
desc = df.describe()
print(desc)
Résultat :
total_bill tip size
count 244.000000 244.000000 244.000000
mean 19.785943 2.998279 2.569672
std 8.902412 1.383638 0.951100
min 3.070000 1.000000 1.000000
25% 13.347500 2.000000 2.000000
50% 17.795000 2.900000 2.000000
75% 24.127500 3.562500 3.000000
max 50.810000 10.000000 6.000000
Les lignes portent des étiquettes textuelles (mean, min, max...). On utilise loc pour extraire une valeur précise :
# Extraire la moyenne de "tip"
mean_tip = desc.loc["mean", "tip"] # â 2.998279
# Extraire le maximum de "total_bill"
max_bill = desc.loc["max", "total_bill"] # â 50.81
Syntaxe : df.loc[étiquette_ligne, nom_colonne]
.values : rĂ©cupĂ©rer le tableau NumPy sous-jacentSous le capot, chaque colonne Pandas est stockĂ©e comme un tableau NumPy. On peut y accĂ©der directement avec .values, ce qui retourne un ndarray prĂȘt Ă ĂȘtre utilisĂ© avec toutes les fonctions NumPy que l'on connait :
import numpy as np
tips = df["tip"].values
print(type(tips)) # <class 'numpy.ndarray'>
print(np.clip(tips, 0, 5)) # plafonner les pourboires Ă 5 $
C'est utile quand on veut appliquer des opérations NumPy (np.clip, np.where, np.mean, etc.) sur des données provenant d'un DataFrame.
| Opération | Syntaxe | Type retourné |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Plusieurs colonnes | df_selection = df[["total_bill", "tip"]] | DataFrame |
| Une colonne (Series) | serie = df["tip"] | Series |
| Une colonne (DataFrame) | df_selection = df[["tip"]] | DataFrame |
| Lignes par position | df_selection = df.iloc[3:10] | DataFrame |
| Ligne précise (Series) | ligne = df.iloc[3] | Series |
| Ligne précise (DataFrame) | df_selection = df.iloc[[3]] | DataFrame |
| Cellule par position | valeur = df.iat[3, 0] | valeur scalaire |
| Cellule par étiquette | valeur = df.at[3, "tip"] | valeur scalaire |
| Cellule avec loc | valeur = df.loc["mean", "tip"] | valeur scalaire |
| Colonne en tableau NumPy | tableau = df["tip"].values | ndarray NumPy |
Les explications de cette section étaient-elles claires ?
Parcourir un DataFrame, câest passer sur chaque ligne ou chaque valeur une par une pour effectuer une opĂ©ration personnalisĂ©e. Câest utile quand on veut faire un traitement pour chaque Ă©lĂ©ment, appliquer une logique conditionnelle complexe, ou encore construire une nouvelle liste Ă partir des donnĂ©es.
Si on nâa besoin que dâune partie des donnĂ©es, on filtre et on trie le DataFrame avant de le parcourir. Parcourir moins de lignes, câest un code plus rapide et plus lisible.
Les exemples qui suivent utilisent le DataFrame df_consoles, qui regroupe des donnĂ©es sur les consoles de jeux vidĂ©o les plus vendues. Chaque ligne reprĂ©sente une console, avec son annĂ©e de sortie, ses ventes estimĂ©es (en millions dâunitĂ©s) et son jeu le plus vendu.
import pandas as pd
df_consoles = pd.DataFrame({
"Console": ["PlayStation 5", "Xbox Series X", "Nintendo Switch 2"],
"Année_Sortie": [2020, 2020, 2025],
"Unités_Vendues_Millions": [92.0, 35.0, 19.6],
})
iterrows() permet de parcourir les lignes dâun DataFrame avec une boucle for. Ă chaque itĂ©ration, on reçoit lâindex de la ligne et son contenu sous forme de Series.
Cette Series a pour index les noms des colonnes du DataFrame. On peut donc accéder à une valeur par nom, exactement comme dans un dictionnaire.
Exemple simple avec une seule colonne :
for index, row in df_consoles.iterrows():
print(row["Console"])
l'instruction row["Console"] retourne la valeur de la colonne Console pour la ligne courante.
Résultat :
PlayStation 5
Xbox Series X
Nintendo Switch 2
Exemple avec plusieurs colonnes :
for index, row in df_consoles.iterrows():
print(f"{row["Console"]} ({row["Année_Sortie"]}) : {row["Unités_Vendues_Millions"]}M unités vendues")
Résultat :
PlayStation 5 (2020) : 92.0M unités vendues
Xbox Series X (2020) : 35.0M unités vendues
Nintendo Switch 2 (2025) : 19.6M unités vendues
index et row sont des conventionsOn peut les remplacer par nâimporte quel nom de variable. for i, ligne in df.iterrows() fonctionne exactement pareil.
iterrows() est lent sur de grands jeux de donnéesPour limiter l'impact, on filtre le DataFrame avant de le parcourir : moins de lignes à traiter, c'est un code plus rapide.
Si le but est de créer de nouvelles colonnes ou modifier des colonnes existantes, iterrows() n'est pas la bonne approche.
Les transformations vectorielles de Pandas sont nettement plus performantes et sont vues dans l'onglet Transformer.
Pour parcourir les valeurs dâune seule colonne (une Series), on itĂšre directement sur la colonne comme sur une liste :
for console in df_consoles["Console"]:
print(console)
Résultat :
PlayStation 5
Xbox Series X
Nintendo Switch 2
Une Series Pandas nâest pas une liste Python ordinaire. Certaines fonctions Python nâacceptent que des listes, pas des Series. Pour convertir, on utilise .tolist() :
liste_consoles = df_consoles["Console"].tolist()
print(liste_consoles) # â [âPlayStation 5â, âXbox Series Xâ, âNintendo Switch 2â]
Certaines fonctions Python sâattendent Ă recevoir une liste et produisent une erreur si on leur passe une Series. .tolist() rĂšgle ce problĂšme.
| Opération | Syntaxe | Description |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Parcourir ligne par ligne | for index, row in df.iterrows(): | index = numéro de ligne, row = Series |
| Accéder à une valeur | row["Console"] | Valeur de la colonne "Console" pour la ligne courante |
| Parcourir une colonne | for val in df["Console"]: | ItĂšre sur les valeurs d'une Series |
| Convertir en liste | df["Console"].tolist() | Retourne une liste Python ordinaire |
Les explications de cette section étaient-elles claires ?
Le principe du Garbage In, Garbage Out s'applique directement en analyse de données : si les données de base sont erronées, tous les calculs qui en découlent le seront aussi.
On nettoie pour trois raisons principales : éviter les erreurs de calcul causées par les valeurs manquantes (NaN, Not A Number), assurer la précision en éliminant les doublons ou les valeurs aberrantes, et faciliter la visualisation en évitant que des points parasites faussent l'échelle d'un graphique.
Les exemples qui suivent utilisent le DataFrame df_joueurs, qui contient des données volontairement imparfaites : valeurs manquantes et doublons inclus.
import pandas as pd
df_joueurs = pd.DataFrame({
"Pseudo": ["Sakura99", "DarkLink", "Sakura99", "NovaStar", "GhostX"],
"Score": [4200, None, 4200, 3100, None],
"Niveau": ["12", None, "12", None, "5"],
"Région": ["QC", "ON", "QC", None, "BC"]
})
Résultat :
Pseudo Score Niveau Région
0 Sakura99 4200.0 12 QC
1 DarkLink NaN NaN ON
2 Sakura99 4200.0 12 QC
3 NovaStar 3100.0 NaN NaN
4 GhostX NaN 5 BC
On remarque déjà que la ligne 2 est un doublon exact de la ligne 0, que Score et Niveau ont des NaN, et que Région est manquante pour NovaStar.
On peut aussi vérifier le type de chaque colonne avec .dtypes :
print(df_joueurs.dtypes)
Résultat :
Pseudo object
Score float64
Niveau object
Région object
dtype: object
La colonne Niveau est de type object, car les valeurs ont été écrites entre guillemets ("12", "5") dans les données de départ.
Pour Pandas, ce ne sont donc pas encore des nombres, mais du texte. On corrigera ce problĂšme plus loin.
Avant de nettoyer, il est utile de savoir quelles colonnes contiennent des NaN et combien. .isnull().sum() retourne le nombre de valeurs manquantes par colonne :
print(df_joueurs.isnull().sum())
Résultat :
Pseudo 0
Score 2
Niveau 2
Région 1
dtype: int64
On voit immédiatement que Score et Niveau ont chacun 2 valeurs manquantes, et que Région en a 1. Pseudo est complet. C'est ce qui guide le choix de nettoyage : quelles colonnes cibler et quelle approche utiliser.
dropna() retourne un nouveau DataFrame sans modifier l'original.
Supprimer toutes les lignes qui contiennent au moins un NaN :
df_propre = df_joueurs.dropna()
print(df_propre)
Résultat :
Pseudo Score Niveau Région
0 Sakura99 4200.0 12 QC
2 Sakura99 4200.0 12 QC
Seules les lignes sans aucun NaN sont conservées. C'est une approche radicale : on perd beaucoup de données.
Supprimer une ligne uniquement si une colonne critique est manquante :
df_propre = df_joueurs.dropna(subset=["Score"])
print(df_propre)
Résultat :
Pseudo Score Niveau Région
0 Sakura99 4200.0 12 QC
2 Sakura99 4200.0 12 QC
3 NovaStar 3100.0 NaN NaN
Cette forme est plus prudente : on ne supprime que les lignes oĂč Score est vide, et on conserve les autres mĂȘme si elles ont d'autres NaN.
dropna() ne modifie pas df_joueurs. Il faut assigner le résultat à une nouvelle variable (ou à df_joueurs pour écraser l'original).
Le réflexe naturel est d'appeler dropna() sans argument pour tout nettoyer d'un coup.
Le problĂšme : on perd souvent des lignes Ă cause de NaN dans des colonnes qu'on n'utilise mĂȘme pas.
On identifie d'abord les colonnes nĂ©cessaires Ă la requĂȘte.
Par exemple, si l'objectif est d'afficher les 3 joueurs avec les meilleurs scores de la région QC :
df_joueurs[df_joueurs["Région"] == "QC"][["Pseudo", "Score"]].sort_values("Score", ascending=False).head(3)
Cette requĂȘte utilise RĂ©gion (filtrer), Score (trier) et Pseudo (afficher). La colonne Niveau n'intervient pas.
df_propre = df_joueurs.dropna() # â perd aussi les lignes oĂč Niveau est NaN
df_propre = df_joueurs.dropna(subset=["RĂ©gion", "Score"]) # â
cible uniquement les colonnes importantes
drop_duplicates() élimine les lignes qui sont des copies exactes d'autres lignes. C'est fréquent lors de la fusion de plusieurs fichiers.
df_propre = df_joueurs.drop_duplicates()
print(df_propre)
Résultat :
Pseudo Score Niveau Région
0 Sakura99 4200.0 12 QC
1 DarkLink NaN NaN ON
3 NovaStar 3100.0 NaN NaN
4 GhostX NaN 5 BC
La ligne 2 (doublon exact de Sakura99) a été supprimée. Pandas conserve la premiÚre occurrence et retire les suivantes.
Comme dropna(), drop_duplicates() ne modifie pas df_joueurs. Il faut assigner le résultat à une nouvelle variable (ou à df_joueurs pour écraser l'original).
Au lieu de supprimer une ligne, on peut parfois remplacer un NaN par une valeur de remplacement.
â ïž Il ne faut toutefois pas remplacer les valeurs manquantes automatiquement. Le choix de la valeur dĂ©pend du contexte, de la colonne et de la question quâon veut analyser.
Quelques stratégies possibles :
| Situation | Exemple de remplacement possible |
|---|---|
| Catégorie inconnue | "Inconnue" |
| Valeur numérique manquante | moyenne, médiane ou valeur fixe |
| Valeur absente qui signifie réellement zéro | 0 |
| Colonne peu importante pour lâanalyse | ne pas remplacer, ou ignorer la colonne |
Les exemples ci-dessous montrent diffĂ©rentes possibilitĂ©s. Ils ne veulent pas dire quâil faut toujours remplacer les valeurs manquantes par la moyenne ou par la mĂ©diane.
Contrairement Ă dropna() et drop_duplicates(), fillna() est ici utilisĂ© pour modifier le contenu d'une colonne directement : on applique une transformation sur la colonne et on rĂ©assigne le rĂ©sultat dans df_joueurs. C'est le mĂȘme principe que les transformations vues dans l'onglet Transformer.
Exemple : remplacer par une valeur fixe (colonne texte)
df_joueurs["Région"] = df_joueurs["Région"].fillna("Inconnue")
print(df_joueurs["Région"])
Résultat :
0 QC
1 ON
2 QC
3 Inconnue
4 BC
Exemple : remplacer par la moyenne de la colonne
moyenne_score = df_joueurs["Score"].mean()
df_joueurs["Score"] = df_joueurs["Score"].fillna(moyenne_score)
print(df_joueurs["Score"])
Résultat :
0 4200.0
1 3766.666...
2 4200.0
3 3100.0
4 3766.666...
Les NaN ont été remplacés par la moyenne des scores existants :
(4200 + 4200 + 3100) / 3 â 3766.
Ce nâest pas une rĂšgle gĂ©nĂ©rale : câest seulement un exemple de stratĂ©gie possible. Dans une vraie analyse, il faudrait se demander si remplacer les scores inconnus par la moyenne a du sens.
On note aussi que le doublon Sakura99 (ligne 2) est inclus dans ce calcul. Si on avait d'abord supprimé les doublons, la moyenne serait différente : (4200 + 3100) / 2 = 3650.
L'ordre des opérations de nettoyage influence donc les résultats.
.mean() s'applique aux colonnes numériques seulementPour une colonne texte, on peut utiliser une valeur fixe comme "Inconnu" ou la valeur la plus fréquente (df["col"].mode()[0]).
astype()Pandas importe parfois des nombres sous forme de texte Ă cause d'un caractĂšre inattendu dans le fichier CSV.
C'est le cas de la colonne Niveau dans df_joueurs : elle a été définie avec des chaßnes de caractÚres comme "12" plutÎt que des entiers.
print(df_joueurs["Niveau"].dtype) # â object (texte)
Avant de pouvoir faire des calculs sur Niveau (moyenne, comparaisons numériques, etc.), il faut d'abord gérer les NaN, puis convertir le type :
# Ătape 1 : remplacer les NaN par 0 (ou une autre valeur appropriĂ©e)
df_joueurs["Niveau"] = df_joueurs["Niveau"].fillna(0)
# Ătape 2 : convertir en nombre
df_joueurs["Niveau"] = df_joueurs["Niveau"].astype(int)
print(df_joueurs["Niveau"].dtype) # â int64
Si la colonne contient des valeurs comme "N/A" ou "â", astype() produira une erreur. Il faut les nettoyer avec fillna() ou replace() avant de convertir.
| Opération | Syntaxe | Description |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Détecter les NaN | df.isnull().sum() | Nombre de NaN par colonne |
| Supprimer les NaN (tout) | df_propre = df.dropna() | Retire toute ligne avec au moins un NaN |
| Supprimer les NaN (colonne) | df_propre = df.dropna(subset=["col"]) | Retire seulement si cette colonne est vide |
| Supprimer les doublons | df_propre = df.drop_duplicates() | Retire les lignes identiques |
| Remplacer les NaN (fixe) | df["col"] = df["col"].fillna("valeur") | Remplace NaN par une valeur fixe |
| Remplacer les NaN (moyenne) | df["col"] = df["col"].fillna(df["col"].mean()) | Remplace NaN par la moyenne (numérique) |
| Convertir le type | df["col"] = df["col"].astype(float) | Change le type de la colonne |
Les explications de cette section étaient-elles claires ?
Transformer un DataFrame, c'est créer ou modifier une colonne à partir des données existantes, sans toucher aux lignes.
On calcule de nouvelles valeurs, on convertit des types ou on remplace des codes par des étiquettes lisibles.
La forme est toujours la mĂȘme : on assigne une expression Ă une colonne du DataFrame.
Si la colonne n'existe pas encore, elle est créée. Si elle existe déjà , son contenu est remplacé :
df["nouvelle_colonne"] = expression # crée une nouvelle colonne
df["colonne_existante"] = expression # modifie une colonne existante
Contrairement au filtrage et au tri (qui retournent un nouveau DataFrame), les transformations modifient df en place en réassignant directement la colonne dans le DataFrame.
En NumPy, on a appris que tableau * 2 applique l'opĂ©ration Ă tous les Ă©lĂ©ments sans boucle. Pandas utilise exactement le mĂȘme principe : df["col"] * 2 applique la multiplication Ă toute la colonne en une seule instruction. On n'a pas besoin de boucle for, pour la mĂȘme raison qu'en NumPy.
Les exemples qui suivent utilisent le fichier tips_dataset.csv chargé dans un DataFrame df :
import pandas as pd
df = pd.read_csv("tips_dataset.csv")
On crée une nouvelle colonne en lui assignant le résultat d'un calcul sur des colonnes existantes :
df["tip_percentage"] = (df["tip"] / df["total_bill"]) * 100
Pour vérifier le résultat, on peut afficher les colonnes source et la nouvelle colonne :
print(df[["total_bill", "tip", "tip_percentage"]].head(3))
Résultat :
total_bill tip tip_percentage
0 16.99 1.01 5.944673
1 10.34 1.66 16.054159
2 21.01 3.50 16.658258
On peut vĂ©rifier mentalement : 1.01 / 16.99 Ă 100 â 5.94 â. La colonne tip_percentage est maintenant disponible dans df comme n'importe quelle autre colonne.
Pandas applique le calcul sur toutes les lignes en une seule instruction, sans avoir besoin d'une boucle for.
C'est ce qu'on appelle une transformation vectorielle : c'est rapide et concis.
bool)On peut créer une colonne dont les valeurs sont True ou False en appliquant une condition sur une colonne existante.
Ces colonnes booléennes sont particuliÚrement utiles pour filtrer ensuite.
Comparaison simple :
df["is_dinner"] = df["time"] == "Dinner"
Comparaison numérique :
df["is_generous"] = df["tip"] > 5
Comparaison avec une liste de valeurs (.isin()) :
df["is_weekend"] = df["day"].isin(["Sun", "Sat"])
Pour visualiser le résultat, on peut afficher les premiÚres lignes avec les colonnes concernées :
print(df[["time", "tip", "day", "is_dinner", "is_generous", "is_weekend"]].head())
Résultat :
time tip day is_dinner is_generous is_weekend
0 Dinner 1.01 Sun True False True
1 Dinner 1.66 Sun True False True
2 Dinner 3.50 Sun True False True
3 Dinner 3.31 Sun True False True
4 Dinner 3.61 Sun True False True
Résumé des colonnes créées :
| Colonne | Type | Description |
|---|---|---|
is_dinner | bool | Vrai si le repas est un souper |
is_generous | bool | Vrai si le pourboire dépasse 5 $ |
is_weekend | bool | Vrai si le jour est samedi ou dimanche |
.isin() vs ==== compare à une seule valeur. .isin([...]) compare à plusieurs valeurs à la fois et est l'équivalent d'un or sur plusieurs ==.
Une fois créées, tip_percentage, is_generous, is_weekend et is_dinner sont disponibles dans df comme n'importe quelle colonne existante. On peut les utiliser pour filtrer, trier, sélectionner ou visualiser, exactement comme on le ferait avec tip ou day.
La méthode map() permet de remplacer chaque valeur d'une colonne par la valeur correspondante dans un dictionnaire.
C'est utile pour convertir des codes en noms lisibles, des abréviations en texte complet, etc.
df_cryptos = pd.DataFrame({
"symbole": ["BTC", "ETH", "SOL", "ADA", "XRP", "DOT"],
"valeur_courante": [94406.0, 3101.57, 137.55, 0.4854, 2.22, 2.80]
})
dict_symboles_noms = {
"BTC": "Bitcoin",
"ETH": "Ethereum",
"SOL": "Solana",
"ADA": "Cardano",
"XRP": "Ripple",
"DOT": "Polkadot"
}
df_cryptos["nom"] = df_cryptos["symbole"].map(dict_symboles_noms)
print(df_cryptos.head())
Résultat :
symbole valeur_courante nom
0 BTC 94406.0000 Bitcoin
1 ETH 3101.5700 Ethereum
2 SOL 137.5500 Solana
3 ADA 0.4854 Cardano
4 XRP 2.2200 Ripple
map() regarde chaque valeur de symbole, cherche la clé correspondante dans le dictionnaire, et retourne une nouvelle colonne avec les noms complets.
Si une valeur de la colonne n'est pas présente comme clé dans le dictionnaire, Pandas la remplace silencieusement par NaN. On s'assure que le dictionnaire couvre toutes les valeurs possibles, ou on vérifie aprÚs coup avec df["col"].isnull().sum().
np.where() vs Pandas : deux façons de faire la mĂȘme choseOn connaĂźt dĂ©jĂ np.where() de la rencontre 10. En Pandas, on peut faire exactement la mĂȘme opĂ©ration avec np.where() directement sur une colonne, ou avec apply() :
import numpy as np
# Avec np.where() (qu'on connaßt déjà de NumPy)
df["categorie"] = np.where(df["tip"] > 5, "généreux", "normal")
# Avec apply() + lambda (façon Pandas)
df["categorie"] = df["tip"].apply(lambda x: "généreux" if x > 5 else "normal")
Les deux produisent le mĂȘme rĂ©sultat. np.where() est plus rapide sur de grands jeux de donnĂ©es; apply est plus lisible pour des conditions complexes.
| Opération | Syntaxe | Description |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Créer une colonne (calcul) | df["col"] = df["a"] + df["b"] | Nouvelle colonne par calcul |
| Créer une colonne (comparaison) | df["col"] = df["a"] > 5 | Nouvelle colonne booléenne |
| Créer une colonne (liste) | df["col"] = df["a"].isin([...]) | Vrai si la valeur est dans la liste |
| Convertir un type | df["col"] = df["col"].astype(float) | Change le type de la colonne |
| Mapper un dictionnaire | df["col"] = df["a"].map(dict) | Remplace les valeurs via un dictionnaire |
Les explications de cette section étaient-elles claires ?
Cet onglet couvre deux niveaux dâanalyse : les statistiques sur une colonne (moyenne, somme, valeurs uniques) et les statistiques par groupe avec groupby(). LâidĂ©e est toujours la mĂȘme : rĂ©sumer les donnĂ©es pour en dĂ©gager des tendances.
Les exemples qui suivent utilisent le fichier tips_dataset.csv chargé dans un DataFrame df :
import pandas as pd
df = pd.read_csv("tips_dataset.csv")
On peut appeler des méthodes statistiques directement sur une colonne (une Series). Voici les essentielles à connaßtre :
On connaĂźt dĂ©jĂ np.mean(), np.min(), np.max() de la rencontre 10. En Pandas, ces mĂȘmes opĂ©rations s'appellent directement sur la colonne : df["col"].mean() plutĂŽt que np.mean(tableau). Le rĂ©sultat est identique, seule la syntaxe change.
print(df["tip"].mean()) # â 2.998... (moyenne)
print(df["tip"].sum()) # â 731.58 (somme)
print(df["tip"].min()) # â 1.0 (minimum)
print(df["tip"].max()) # â 10.0 (maximum)
print(df["tip"].median()) # â 2.9 (mĂ©diane)
print(df["tip"].count()) # â 244 (nombre de valeurs non-nulles)
LâĂ©cart-type std() et la variance var() mesurent la dispersion des donnĂ©es autour de la moyenne. Utiles en statistiques, mais moins prioritaires pour dĂ©buter.
Pour une colonne textuelle, plutĂŽt que des moyennes, on veut savoir quelles valeurs existent et combien de fois elles apparaissent.
Lister les valeurs distinctes et leur fréquence :
print(df["day"].value_counts())
Résultat :
day
Sat 87
Sun 76
Thur 62
Fri 19
Name: count, dtype: int64
value_counts() retourne les valeurs triĂ©es du plus frĂ©quent au moins frĂ©quent. Câest souvent la premiĂšre chose Ă faire sur une colonne textuelle.
Lister les valeurs uniques et en compter le nombre :
print(df["day"].unique()) # â [âSunâ âSatâ âThurâ âFriâ]
print(df["day"].nunique()) # â 4
On constate quâil nây a que 4 jours dans le jeu de donnĂ©es : lundi, mardi et mercredi sont absents.
nunique() vs unique()nunique() ne compte pas les NaN, alors que unique() les inclut dans la liste.
groupby()groupby() permet de diviser le DataFrame en groupes selon les valeurs dâune colonne, puis dâappliquer une fonction statistique sur chaque groupe.
Pandas suit trois étapes : il sépare les lignes en groupes, applique une fonction sur chacun, puis combine les résultats en une Series ou un DataFrame.
Exemple â pourboire moyen par jour :
tip_par_jour = df.groupby("day")["tip"].mean()
print(tip_par_jour)
Résultat : (une Series)
day
Fri 2.734737
Sat 2.993103
Sun 3.255132
Thur 2.771452
Name: tip, dtype: float64
La colonne de regroupement (day) devient lâindex du rĂ©sultat (Fri, Sat, ...), et les valeurs sont les statistiques calculĂ©es par groupe (2.734737, 2.993103, ...).
Plusieurs statistiques Ă la fois avec agg() :
df_stats = df.groupby("day")["tip"].agg(["mean", "sum", "count"])
print(df_stats)
Résultat : (un DataFrame, avec une colonne par statistique)
mean sum count
day
Fri 2.734737 51.96 19
Sat 2.993103 260.40 87
Sun 3.255132 247.39 76
Thur 2.771452 171.83 62
On peut aussi regrouper selon plusieurs colonnes, ici sex et day, puis calculer plusieurs statistiques, ici mean et count, sur plusieurs colonnes numériques, ici tip et total_bill :
df.groupby(["sex", "day"])[["tip", "total_bill"]].agg(["mean", "count"])
Cela produit un DataFrame avec un index hiérarchique sur les lignes (sex, puis day) et des colonnes hiérarchiques (tip/total_bill, puis mean/count).
Résultat possible :
tip total_bill
mean count mean count
sex day
Female Fri 2.781111 9 14.145556 9
Sat 2.801786 28 19.680357 28
Sun 3.367222 18 19.872222 18
Thur 2.575625 32 16.715312 32
Male Fri 2.693000 10 19.857000 10
Sat 3.083898 59 20.802542 59
Sun 3.220345 58 21.887241 58
Thur 2.980333 30 18.714667 30
Par exemple, la ligne Female / Fri donne les statistiques des factures du vendredi pour les clientes identifiées comme Female.
Utile pour des analyses croisées, mais la lecture du résultat est plus complexe.
pivot_table() ressemble à groupby(), mais organise les résultats en tableau à deux dimensions pour faciliter la comparaison visuelle.
On choisit ce qui va sur les lignes, ce qui va sur les colonnes, et quelle valeur on calcule dans les cellules.
df_pivot = df.pivot_table(
values="tip", # valeur Ă calculer
index="size", # regroupement sur les lignes
columns="day", # regroupement sur les colonnes
aggfunc="mean" # fonction statistique
)
print(df_pivot)
Résultat :
day Fri Sat Sun Thur
size
1 1.000000 2.000000 1.500000 NaN
2 2.250000 2.592857 3.070588 2.428571
3 3.000000 3.622222 3.050000 2.250000
4 1.500000 3.500000 4.030303 3.683333
5 NaN 2.750000 4.566667 2.600000
6 NaN 5.000000 NaN 5.300000
Chaque cellule contient le pourboire (tip) moyen (mean) pour une taille de groupe (size) et un jour (day) donnĂ©s. Les NaN indiquent quâaucune donnĂ©e nâexiste pour cette combinaison.
| Opération | Syntaxe | Description |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Moyenne | moyenne = df["col"].mean() | Moyenne des valeurs |
| Somme | somme = df["col"].sum() | Somme des valeurs |
| Minimum / Maximum | minimum = df["col"].min() | Valeur minimale ou maximale |
| Médiane | mediane = df["col"].median() | Valeur médiane |
| Nombre de valeurs | nb_valeurs = df["col"].count() | Valeurs non-nulles |
| Fréquences | frequences = df["col"].value_counts() | Fréquence de chaque valeur |
| Valeurs uniques | uniques = df["col"].unique() | Liste des valeurs distinctes |
| Nombre de valeurs uniques | nb_uniques = df["col"].nunique() | Nombre de valeurs distinctes |
| Grouper + statistique | df_groupe = df.groupby("col")["val"].mean() | Statistique par groupe |
| Grouper + plusieurs stats | df_groupe = df.groupby("col")["val"].agg([...]) | Plusieurs stats par groupe |
| Table de pivot | df_pivot = df.pivot_table(values=..., index=..., columns=...) | Tableau croisé de statistiques |
Les explications de cette section étaient-elles claires ?