đŒ 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 ?
Une fois les données nettoyées, transformées ou analysées, on veut souvent les sauvegarder pour les réutiliser ailleurs : les partager avec un collÚgue, les intégrer dans une autre application. Pandas permet d'exporter un DataFrame en quelques lignes.
Les exemples qui suivent utilisent le fichier tips_dataset.csv chargé et transformé dans un DataFrame df :
import pandas as pd
df = pd.read_csv("tips_dataset.csv")
df["tip_percentage"] = (df["tip"] / df["total_bill"]) * 100
On prépare d'abord le DataFrame à exporter en enchaßnant les manipulations souhaitées. Ici, on filtre les repas du soir avec un pourboire supérieur à 15 % et on trie par pourcentage décroissant :
df_export = df[(df["time"] == "Dinner") & (df["tip_percentage"] > 15)].sort_values("tip_percentage", ascending=False)
df_export est maintenant prĂȘt Ă ĂȘtre sauvegardĂ© dans le format de son choix.
Le format CSV est le plus universel : lisible par Excel, Python, R, et la plupart des outils d'analyse.
df_export.to_csv("soupers_genereux.csv", index=False)
Le fichier soupers_genereux.csv est créé dans le mĂȘme dossier que le script.
index=FalsePar dĂ©faut, Pandas ajoute une colonne d'index (0, 1, 2...) au dĂ©but du fichier. index=False Ă©vite cette colonne, souvent inutile dans un fichier CSV destinĂ© Ă ĂȘtre lu par d'autres outils.
| Opération | Syntaxe | Description |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Exporter en CSV | df.to_csv("fichier.csv", index=False) | Fichier CSV sans colonne d'index |
Les explications de cette section étaient-elles claires ?
Pandas s'intÚgre directement avec Matplotlib pour générer des graphiques à partir d'un DataFrame.
On importe les deux bibliothÚques, on charge les données, et on trace en quelques lignes seulement.
Pour se rafraßchir la mémoire sur Matplotlib, on peut consulter l'onglet Matplotlib de la rencontre 9.
Pour aller plus loin, on peut aussi consulter la documentation officielle de Matplotlib.
Les exemples qui suivent utilisent le fichier tips_dataset.csv chargé dans un DataFrame df, avec une colonne calculée tip_percentage :
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("tips_dataset.csv")
df["tip_percentage"] = (df["tip"] / df["total_bill"]) * 100
Un histogramme montre comment les valeurs d'une colonne sont réparties (sa distribution). L'axe des X est divisé en intervalles de valeurs, et l'axe Y indique combien de données tombent dans chaque intervalle. Le paramÚtre bins détermine le nombre d'intervalles. Pandas calcule automatiquement la largeur de chaque intervalle en divisant l'écart entre la valeur minimale et maximale par le nombre de bins :
largeur d'un intervalle = (max â min) / bins
Par exemple, si tip_percentage va de 3 % Ă 71 % et qu'on demande bins=20, chaque intervalle aura une largeur d'environ (71 â 3) / 20 â 3,4 %.
df["tip_percentage"].hist(
bins=20 # diviser en 20 intervalles
)
plt.title("Distribution du pourcentage de pourboire")
plt.xlabel("Pourcentage de pourboire (%)")
plt.ylabel("Fréquence")
plt.grid(axis='both', linestyle='--', linewidth=0.5)
plt.show()

Une boßte à moustaches (boxplot) montre la distribution d'une variable numérique pour chaque groupe. Voici comment lire chaque élément du graphique :
Comment interpréter une boßte à moustaches :
- La ligne du milieu (orange) représente la médiane : 50 % des valeurs sont en dessous, 50 % au-dessus.
- Le bas de la boßte représente le 1er quartile (Q1) : 25 % des valeurs sont en dessous.
- Le haut de la boßte représente le 3e quartile (Q3) : 75 % des valeurs sont en dessous.
- La hauteur de la boĂźte est l'intervalle interquartile (IQR) = Q3 â Q1 : il contient le 50 % central des donnĂ©es.
- Les moustaches (les traits) s'étendent jusqu'à 1,5 à IQR au-delà de Q1 et Q3.
- Les cercles (âą) sont les valeurs aberrantes (outliers) : valeurs qui dĂ©passent les moustaches.
df.boxplot(
column="tip_percentage", # axe des y
by="day" # regroupement (axe des x)
)
plt.title("Pourcentage de pourboire par jour")
plt.suptitle("") # retire le titre autogénéré
plt.xlabel("Jour")
plt.ylabel("Pourcentage de pourboire (%)")
plt.grid(axis='both', linestyle='--', linewidth=0.5)
plt.show()

Un nuage de points (scatter plot) montre la relation entre deux variables numériques. On peut ajouter une troisiÚme variable en faisant varier la taille des points.
plt.scatter(
x=df["total_bill"], # axe des x
y=df["tip"], # axe des y
s=df["size"] * 20, # taille des points
# (Ă20 pour la visibilitĂ©)
alpha=0.5 # opacité
)
plt.xlabel("Montant total de la facture ($)")
plt.ylabel("Pourboire ($)")
plt.title("Pourboire en fonction du montant " +
"total de la facture\n" +
"(taille â nombre de convives)")
plt.grid(axis='both', linestyle='--', linewidth=0.5)
plt.show()

En combinant pivot_table() et .plot(), on peut tracer plusieurs courbes sur un mĂȘme graphique pour comparer des tendances selon une variable catĂ©gorielle.
df["is_weekend"] = df["day"].isin(["Sun", "Sat"])
df_pivot = df.pivot_table(
values="tip", # axe des y
index="size", # axe des x
columns="is_weekend", # une courbe par groupe
aggfunc="mean"
)
df_pivot.plot(marker="o")
plt.xlabel("Taille du groupe")
plt.ylabel("Pourboire moyen ($)")
plt.title("Pourboire en fonction " +
"de la taille du groupe\n" +
"(par jour de la semaine)")
plt.legend(
title="Jour de la semaine",
labels=["Jour de semaine", "Fin de semaine"]
)
plt.grid(axis='both', linestyle='--', linewidth=0.5)
plt.show()

| Graphique | Syntaxe | Usage |
|---|---|---|
| Importer Pandas | import pandas as pd | Convention universelle |
| Importer Matplotlib | import matplotlib.pyplot as plt | Convention universelle |
| Histogramme | df["col"].hist(bins=20) | Distribution d'une colonne numérique |
| BoĂźte Ă moustaches | df.boxplot(column="col", by="groupe") | Distribution par groupe |
| Nuage de points | plt.scatter(x=df["x"], y=df["y"]) | Relation entre deux variables |
| Courbes groupées | df.pivot_table(...).plot() | Tendances par groupe |
| Afficher | plt.show() | Afficher le graphique |
Les explications de cette section étaient-elles claires ?
Pour favoriser une progression efficace, ce cours adopte une approche de classe inversée. Ce modÚle déplace l'acquisition théorique hors de la classe pour transformer les heures de rencontre en véritables séances d'application pratique.
-
Ă la maison (Exploration et Appropriation) : Vous ĂȘtes le maĂźtre de votre rythme. Ces activitĂ©s vous permettent de dĂ©couvrir les nouveaux concepts et tester les exemples au moment oĂč vous ĂȘtes le plus concentrĂ©. Si une notion vous semble obscure, n'hĂ©sitez pas Ă poser des questions Ă votre prof au fur et Ă mesure.
-
En classe (Application et Consolidation) : Le temps en prĂ©sentiel est une ressource prĂ©cieuse. Nous l'utilisons pour nous attaquer aux dĂ©fis plus complexes et aux exercices de programmation qui demandent une mobilisation active de vos connaissances. Câest le moment idĂ©al pour obtenir une rĂ©troaction immĂ©diate, collaborer avec vos pairs et bĂ©nĂ©ficier de l'accompagnement de votre enseignant au moment oĂč vous en avez le plus besoin.
- đ ActivitĂ©s Ă faire Ă la maison
- đ« ActivitĂ©s Ă faire en classe
đ§ Auto-validation des connaissancesâ
Ce formulaire sert à vérifier votre compréhension des éléments les plus importants de la rencontre R11. Ne faites ce questionnaire que lorsque vous vous sentez en trÚs bonne maßtrise de la matiÚre. En classe, dÚs votre arrivée, vous aurez un questionnaire trÚs similaire, évalué sommativement, à compléter sans accÚs à aucune documentation.
Ne pas remplir le formulaire diminue fortement vos chances de rĂ©ussir lâĂ©valuation sommative en dĂ©but de rencontre.
Assurez-vous de bien comprendre toutes les notions derriĂšre chaque question.
đš Exercices de crĂ©ationâ
Pour chacun des exercices de cette section, vous devez créer des fichiers .py avec les noms indiqués.
Pour les exercices de cette section, vous pouvez consulter librement la documentation du site web du cours.
đ CrĂ©ez un fichier r11_modeles_vehicules.py pour votre rĂ©ponse.
TĂ©lĂ©chargez le fichier mpg_dataset.csv et placez-le dans le mĂȘme dossier que votre script.
Exploration
- Chargez les données dans un DataFrame.
- Affichez le résumé technique avec
info()(types, valeurs manquantes, taille). - Affichez les types de données de chaque colonne avec
dtypes. - Affichez les statistiques descriptives avec
describe().
Résultat attendu pour dtypes :
mpg float64
cylinders int64
displacement float64
horsepower float64
weight int64
acceleration float64
model_year int64
origin object
name object
dtype: object
Résultat attendu pour describe() :
mpg cylinders displacement horsepower weight acceleration model_year
count 398.000000 398.000000 398.000000 392.000000 398.000000 398.000000 398.000000
mean 23.514573 5.454774 193.425879 104.469388 2970.424623 15.568090 76.010050
std 7.815984 1.701004 104.269838 38.491160 846.841774 2.757689 3.697627
min 9.000000 3.000000 68.000000 46.000000 1613.000000 8.000000 70.000000
25% 17.500000 4.000000 104.250000 75.000000 2223.750000 13.825000 73.000000
50% 23.000000 4.000000 148.500000 93.500000 2803.500000 15.500000 76.000000
75% 29.000000 8.000000 262.000000 126.000000 3608.000000 17.175000 79.000000
max 46.600000 8.000000 455.000000 230.000000 5140.000000 24.800000 82.000000
Filtrage et tri
- Filtrez et affichez les modÚles japonais ayant une accélération de 19.4 et plus.
Résultat attendu :
Les modÚles japonais ayant une accélération de 19.4 et plus :
- toyota corolla 1200
- mazda glc deluxe
- datsun 210 mpg
- Filtrez et affichez les 5 voitures avec le plus de horsepower.
Résultat attendu :
Les 5 voitures avec le plus de horsepower :
- horsepower : 230.0 - pontiac grand prix
- horsepower : 225.0 - buick electra 225 custom
- horsepower : 225.0 - pontiac catalina
- horsepower : 225.0 - buick estate wagon (sw)
- horsepower : 220.0 - chevrolet impala
Comptage
- Affichez le nombre de voitures japonaises avec un poids supérieur à 2500.
Résultat attendu :
Le nombre de voitures japonaises avec un poids supérieur à 2500 : 17
Exportation
- Filtrez le DataFrame pour ne conserver que les voitures japonaises, puis exportez ce nouveau DataFrame dans un fichier nommé
mpg_japonaises.csvsans l'index. Ouvrez ensuite le fichier dans un éditeur ou un tableur pour vérifier qu'il ne contient bien que des voitures japonaises.
Pandas, chargement CSV read_csv(), info(), dtypes, describe(), filtrage booléen, tri sort_values(), comptage, exportation to_csv()
đ CrĂ©ez un fichier r11_prix_turing.py pour votre rĂ©ponse.
TĂ©lĂ©chargez le fichier Turing.csv et placez-le dans le mĂȘme dossier que votre script. Il contient tous les gagnants du Prix Turing.
Exploration
- Chargez les données dans un DataFrame.
- Affichez le nombre de lignes et de colonnes du DataFrame ainsi que la liste de ses colonnes.
Résultat attendu :
Dimensions : (79, 4)
Colonnes : ['year', 'laureate', 'contribution', 'affiliation']
Comptage
- Affichez le nombre total de lauréats.
Résultat attendu :
Nombre total de lauréats : 79
Filtrage
- Affichez les lauréats dont la contribution contient le mot
'intelligence'.
Résultat attendu :
Lauréats avec 'intelligence' dans la contribution :
- Marvin Minsky
- Allen Newell
- Herbert A. Simon
- Raj Reddy
- Affichez les lauréats affiliés à MIT ou Stanford.
Résultat attendu :
Lauréats affiliés à MIT ou Stanford :
- Marvin Minsky (MIT)
- John McCarthy (Stanford University)
- Donald E. Knuth (Stanford University)
- Robert W. Floyd (Stanford University)
- Fernando J. CorbatĂł (MIT)
- Edward A. Feigenbaum (Stanford University)
- Douglas C. Engelbart (Stanford Research Institute (SRI))
- Ronald L. Rivest (MIT)
- Barbara H. Liskov (MIT)
- Shafi Goldwasser (MIT / Weizmann Institute)
- Silvio Micali (MIT)
- Michael Stonebraker (MIT)
- Whitfield Diffie (Stanford / Sun Microsystems)
- Martin E. Hellman (Stanford University)
- Tim Berners-Lee (CERN / W3C / MIT)
- John L. Hennessy (Stanford University)
- Patrick M. Hanrahan (Stanford University / Pixar)
- Jeffrey D. Ullman (Stanford University)
- Affichez les lauréats ayant reçu le prix entre 1980 et 1990 inclusivement.
Résultat attendu :
Lauréats entre 1980 et 1990 :
- 1980 : C.A.R. (Tony) Hoare
- 1981 : Edgar F. Codd
- 1982 : Stephen A. Cook
- 1983 : Kenneth L. Thompson
- 1983 : Dennis M. Ritchie
- 1984 : Niklaus Wirth
- 1985 : Richard M. Karp
- 1986 : John E. Hopcroft
- 1986 : Robert E. Tarjan
- 1987 : John Cocke
- 1988 : Ivan E. Sutherland
- 1989 : William (Velvel) Kahan
- 1990 : Fernando J. CorbatĂł
- Affichez les 5 lauréats les plus récents.
Résultat attendu :
Les 5 lauréats les plus récents :
- 2024 : Richard S. Sutton
- 2024 : Andrew G. Barto
- 2023 : Avi Wigderson
- 2022 : Robert M. Metcalfe
- 2021 : Jack J. Dongarra
Statistiques
-
Créez une nouvelle colonne
decennieen appliquant la formule(year // 10) * 10utilisant la colonneyear(ex. 1986 â 1980, 2023 â 2020). -
Affichez le nombre de lauréats par décennie. (indice : regroupement + compte)
Résultat attendu :
Lauréats par décennie :
- 1960s : 4 lauréats
- 1970s : 12 lauréats
- 1980s : 12 lauréats
- 1990s : 12 lauréats
- 2000s : 16 lauréats
- 2010s : 16 lauréats
- 2020s : 7 lauréats
Pandas, dimensions (shape), liste des colonnes, filtrage par texte str.contains(), conditions multiples (|), tri, création de nouvelle colonne, regroupement groupby() et comptage
đ CrĂ©ez un fichier r11_groupby_moyenne.py pour votre rĂ©ponse.
TĂ©lĂ©chargez le fichier tips_dataset.csv et placez-le dans le mĂȘme dossier que votre script.
- Chargez les données dans un DataFrame.
- Calculez et affichez la facture moyenne (
total_bill) par jour de la semaine.
Résultat attendu :
day
Fri 17.151579
Sat 20.441379
Sun 21.410000
Thur 17.682742
Name: total_bill, dtype: float64
- Calculez et affichez le total des pourboires (
tip) par moment de la journée (dßner/lunch).
Résultat attendu :
time
Dinner 546.07
Lunch 185.51
Name: tip, dtype: float64
- Calculez et affichez la taille moyenne du groupe (
size) par jour de la semaine.
Résultat attendu :
day
Fri 2.105263
Sat 2.517241
Sun 2.842105
Thur 2.451613
Name: size, dtype: float64
- Calculez et affichez le nombre de repas par sexe (
sex).
Résultat attendu :
sex
Female 87
Male 157
Name: total_bill, dtype: int64
- Calculez et affichez la facture moyenne par statut fumeur (
smoker).
Résultat attendu :
smoker
No 19.188278
Yes 20.756344
Name: total_bill, dtype: float64
En observant ces résultats, répondez aux questions suivantes :
- Quel jour de la semaine génÚre les factures les plus élevées? Et le plus faibles?
- Le dßner ou le lunch génÚre-t-il plus de pourboires au total? Pourquoi selon vous?
- Est-ce que les fumeurs dépensent plus en moyenne que les non-fumeurs?
- Quel jour vient-on en plus grand groupe? Est-ce cohérent avec la facture moyenne de ce jour?
- Les hommes ou les femmes viennent-ils manger plus souvent au restaurant?
Pandas, regroupement groupby(), fonctions d'agrégation (mean, sum, count), interprétation de résultats
đ CrĂ©ez un fichier r11_nettoyage_selection.py pour votre rĂ©ponse.
Un registraire de cégep dispose d'un tableau d'étudiants en Sciences de la nature contenant des données manquantes et des doublons. Les programmes sont :
- 200.BA : Sciences de la santé
- 200.BB : Sciences pures et appliquées
- 200.BC : Sciences de la nature (Découverte / Enrichi)
Utilisez le dictionnaire suivant pour créer votre DataFrame :
import pandas as pd
data = {
'prenom': ['LĂ©a', 'Mathis', 'LĂ©a', 'Yasmine', 'Tristan', None, 'Ămile'],
'programme': ['200.BA', '200.BB', '200.BA', '200.BC', '200.BA', '200.BB', '200.BC'],
'session': [3, None, 3, 2, None, 4, 1],
'note_finale': [78, 85, 78, None, 91, 67, None],
'nb_absences': [2, 0, 2, 5, None, 1, 3]
}
df = pd.DataFrame(data)
Le DataFrame initial ressemble Ă ceci :
prenom programme session note_finale nb_absences
0 Léa 200.BA 3.0 78.0 2.0
1 Mathis 200.BB NaN 85.0 0.0
2 Léa 200.BA 3.0 78.0 2.0
3 Yasmine 200.BC 2.0 NaN 5.0
4 Tristan 200.BA NaN 91.0 NaN
5 NaN 200.BB 4.0 67.0 1.0
6 Ămile 200.BC 1.0 NaN 3.0
Nettoyage
- Affichez les lignes ne contenant aucune valeur manquante.
Résultat attendu :
prenom programme session note_finale nb_absences
0 Léa 200.BA 3.0 78.0 2.0
2 Léa 200.BA 3.0 78.0 2.0
- Remplacez les valeurs manquantes comme suit, puis affichez le DataFrame corrigé :
session: remplacez par la moyenne des sessionsnote_finale: remplacez par la médiane des notesnb_absences: remplacez par0
Résultat attendu :
prenom programme session note_finale nb_absences
0 Léa 200.BA 3.0 78.0 2.0
1 Mathis 200.BB 2.6 85.0 0.0
2 Léa 200.BA 3.0 78.0 2.0
3 Yasmine 200.BC 2.0 78.0 5.0
4 Tristan 200.BA 2.6 91.0 0.0
5 NaN 200.BB 4.0 67.0 1.0
6 Ămile 200.BC 1.0 78.0 3.0
Continuez avec ce DataFrame corrigé pour les étapes suivantes.
- Supprimez les lignes dupliquées et affichez le DataFrame résultant.
Résultat attendu :
prenom programme session note_finale nb_absences
0 Léa 200.BA 3.0 78.0 2.0
1 Mathis 200.BB 2.6 85.0 0.0
3 Yasmine 200.BC 2.0 78.0 5.0
4 Tristan 200.BA 2.6 91.0 0.0
5 NaN 200.BB 4.0 67.0 1.0
6 Ămile 200.BC 1.0 78.0 3.0
Sélection
- à partir du DataFrame corrigé (avant suppression des doublons), affichez le prénom et la note finale des étudiants en 200.BA (Sciences de la santé).
Résultat attendu :
prenom note_finale
0 Léa 78.0
2 Léa 78.0
4 Tristan 91.0
- Affichez les 3 premiĂšres lignes et les colonnes
prenom,programmeetsessiondu DataFrame corrigé.
Résultat attendu :
prenom programme session
0 Léa 200.BA 3.0
1 Mathis 200.BB 2.6
2 Léa 200.BA 3.0
Création d'un DataFrame depuis un dictionnaire, valeurs manquantes dropna(), fillna(), mean/median, suppression de doublons drop_duplicates(), sélection de colonnes et de lignes loc, iloc, head()
đ CrĂ©ez un fichier r11_pourboire_par_personne.py pour votre rĂ©ponse.
TĂ©lĂ©chargez le fichier tips_dataset.csv et placez-le dans le mĂȘme dossier que votre script.
Transformation
- Chargez les données dans un DataFrame.
- Créez une nouvelle colonne
tip_par_personqui calcule le pourboire par personne (tipdivisé parsize). - Affichez les 5 premiÚres lignes du DataFrame modifié.
Résultat attendu :
total_bill tip sex smoker day time size tip_par_person
0 16.99 1.01 Female No Sun Dinner 2 0.505000
1 10.34 1.66 Male No Sun Dinner 3 0.553333
2 21.01 3.50 Male No Sun Dinner 3 1.166667
3 23.68 3.31 Male No Sun Dinner 2 1.655000
4 24.59 3.61 Female No Sun Dinner 4 0.902500
Visualisation
- Générez un histogramme de
tip_par_personavecbins=10pour visualiser la distribution des pourboires par personne. - Générez un boxplot de
tip_par_personregroupé par taille de groupe (size) pour voir comment le pourboire par personne varie selon la taille du groupe.
Résultats attendus :


Voyez-vous des tendances intéressantes ? Par exemple, est-ce que le pourboire par personne augmente ou diminue avec la taille du groupe?
Pandas, création de colonne calculée, head(), visualisation (histogramme avec bins, boxplot par groupe)
âïž Exercices sur papierâ
Les exercices suivants ne visent pas nécessairement à pratiquer la matiÚre de cette rencontre,
mais plutÎt à vous entraßner à l'écriture de code "papier" sur des concepts plus simples, comme il pourrait y avoir à l'examen.
Faites ces exercices d'abord sur papier (ou dans un éditeur de texte simple) et sans aucune documentation, comme à l'examen.
Vous pouvez valider votre rĂ©ponse dans PyCharm Ă la fin â un luxe que vous n'aurez pas le jour de l'examen, d'oĂč l'importance de vous entraĂźner sans lui.
Sur papier, sans ordinateur, écrivez un code demandant à l'utilisateur de saisir un nombre.
Tant que le nombre saisi est positif, le programme redemande de saisir un nouveau nombre.
Lorsqu'un nombre saisi est négatif, le programme affiche tous les nombres saisis ainsi que leur somme.
Le programme prend alors fin.
Exemple d'exĂ©cutionâ
Saisir un nombre : 20
Saisir un nombre : 50
Saisir un nombre : 10
Saisir un nombre : -5
Nombres saisis : [20, 50, 10, -5]
Somme : 75
đ CrĂ©ez un fichier r11_sans_pycharm.py pour valider votre rĂ©ponse Ă l'aide de Pycharm.
Boucle while, saisie utilisateur input(), accumulation dans une liste, calcul de somme
đŻ Solutions des exercices
Un solutionnaire possible pour chaque exercice est disponible en format vidĂ©o avec des explications. Vous pouvez vous en servir pour comparer votre solution avec une solution possible jugĂ©e optimale et vous dĂ©bloquer aprĂšs un long moment bloquĂ© sur un exercice (ex. 20 minutes) et aprĂšs avoir utilis Ă© le dĂ©bogueur pour essayer par vous-mĂȘme de trouver le problĂšme.
Il est tout Ă fait normal que certains problĂšmes demandent du temps, de la rĂ©flexion, et parfois mĂȘme un peu de frustration. Câest prĂ©cisĂ©ment dans ces moments dâeffort que lâapprentissage sâancre rĂ©ellement.
Consulter un solutionnaire avant dâavoir tentĂ© lâexercice par soi-mĂȘme, ou le parcourir trop rapidement, revient Ă court-circuiter le processus dâapprentissage. Ce nâest pas simplement contre-productif, câest pĂ©dagogiquement dĂ©sastreux.
En sautant lâĂ©tape de la rĂ©flexion personnelle, on prive son cerveau de lâoccasion de construire des connexions durables. Et Ă force de rĂ©pĂ©ter ce rĂ©flexe, on risque de passer Ă cĂŽtĂ© des compĂ©tences essentielles, ce qui peut mener Ă des Ă©checs plus tard, mĂȘme si tout semble facile sur le moment. Alors oui, prenez le temps. Lâerreur fait partie du jeu. Câest en cherchant, en tĂątonnant, en doutant, quâon devient rĂ©ellement compĂ©tent. Le solutionnaire doit ĂȘtre un outil de validation, pas un raccourci.
đš Solution des exercices de crĂ©ation :
- Analyse : ModÚles de véhicules
- Analyse : Prix Turing
- groupby et moyenne
- Nettoyage et sélection de données
- Visualisation : Pourboire par personne
âïž Solution des exercices sur papier :