Les fondamentaux de pandas : Series, DataFrames, le DatetimeIndex, sélection et filtrage, et rééchantillonnage des barres journalières en hebdomadaires
Comprenez les Series et les DataFrames, indexez les données de prix par date, sélectionnez des lignes avec loc et iloc, filtrez avec des masques booléens et agrégez des barres journalières en barres hebdomadaires.
Ce que vous allez apprendre
- Ce que sont une
Serieset unDataFrame, et pourquoi leDatetimeIndexest la colonne vertébrale de l'analyse des prix. - La différence entre
loc, fondé sur les étiquettes, etiloc, fondé sur les positions, et la manière dont les masques booléens filtrent les lignes. - Comment construire des barres hebdomadaires ou mensuelles à partir de barres journalières avec
resampleet la bonne agrégation pour chaque colonne. - Quels comportements par défaut de pandas ont changé avec la version 3.0 et comment écrire du code qui se comporte de la même façon en 2.2 et en 3.x.
Explication
Une Series est un tableau étiqueté à une dimension : une colonne de clôtures avec une date associée à chaque valeur. Un DataFrame est une table de Series qui partagent un même index : ouverture, plus haut, plus bas, clôture et volume côte à côte. L'index contient les étiquettes des lignes ; pour des données de prix, ce doit être un DatetimeIndex, un index spécialisé de timestamps qui permet le découpage par dates, le rééchantillonnage et la gestion des fuseaux horaires. Convention : import pandas as pd.
Créez un DataFrame à partir d'un dictionnaire de colonnes et d'un index de dates :
idx = pd.bdate_range("2025-03-03", periods=10)
df = pd.DataFrame({"open": [...], "high": [...], "low": [...], "close": [...], "volume": [...]}, index=idx)
bdate_range ne produit que des jours ouvrés et ignore tout des jours fériés boursiers ; les vraies données proviennent de fichiers (leçon 4). Inspectez avec df.head(), df.info() (types et valeurs manquantes) et df.describe(). df.index.dtype doit afficher datetime64 ; s'il affiche object, les dates sont encore du texte.
Sélectionner. df["close"] renvoie une Series ; df[["open", "close"]] (une liste) renvoie un DataFrame. df.loc[row_labels, columns] sélectionne par étiquette : df.loc["2025-03-05":"2025-03-07", "close"] donne les clôtures de ces trois dates, et avec loc les deux bornes d'un découpage sont incluses, contrairement aux listes Python. df.iloc[0:3] sélectionne par position entière (les trois premières lignes, fin exclue) et df.iloc[-1] est la dernière barre.
Filtrer. Une comparaison sur une Series produit une Series de booléens, un masque : up = df["close"] > df["open"]. Passer le masque sélectionne les lignes correspondantes : df[up]. Combinez les masques avec & (et), | (ou) et ~ (non), chaque condition entre ses propres parenthèses : df[(df["close"] > df["open"]) & (df["volume"] > 1200)]. up.sum() compte les valeurs True, et up.mean() est la proportion de jours haussiers.
Ajouter des colonnes se fait par affectation : df["range"] = df["high"] - df["low"]. Les opérations sont vectorisées, c'est-à-dire appliquées à des colonnes entières d'un coup, ce qui explique la rapidité de pandas. shift(1) décale les valeurs d'une ligne vers le bas (la clôture de la veille sur la ligne du jour) et pct_change() donne les variations en pourcentage ; tous deux laissent un NaN (not a number, « pas un nombre ») sur la première ligne.
Rééchantillonner. resample regroupe les lignes dans des intervalles de temps fixes. Chaque colonne a besoin de sa propre règle : l'ouverture hebdomadaire est la première ouverture journalière, le plus haut est le maximum, le plus bas le minimum, la clôture la dernière, et le volume la somme :
rules = {"open": "first", "high": "max", "low": "min", "close": "last", "volume": "sum"}
weekly = df.resample("W-FRI").agg(rules)
Le code "W-FRI" étiquette chaque semaine par son vendredi. Les barres mensuelles utilisent "ME" (fin de mois). Les anciens tutoriels écrivent "M" ; pandas 2.2 a déprécié cet alias au profit de "ME" (de même "QE" et "YE"), et le code écrit avec les nouveaux alias fonctionne en 2.2 comme en 3.x.
Changements de pandas 3.0 à connaître. Le Copy-on-Write est désormais le seul mode : un DataFrame filtré est une copie indépendante, donc df[mask]["close"] = 0 ne modifie jamais df ; écrivez df.loc[mask, "close"] = 0. Les colonnes de texte ont maintenant le dtype str au lieu de object.
Exemple commenté
Exemple hypothétique : dix barres journalières du lundi 3 mars au vendredi 14 mars 2025, prix en euros, sans jour férié.
| Date | Ouverture | Plus haut | Plus bas | Clôture | Volume |
|---|---|---|---|---|---|
| 03 mars | 100 | 102 | 99 | 101 | 1,000 |
| 04 mars | 101 | 104 | 100 | 103 | 1,200 |
| 05 mars | 103 | 104 | 101 | 102 | 900 |
| 06 mars | 102 | 105 | 101 | 104 | 1,100 |
| 07 mars | 104 | 106 | 103 | 105 | 1,500 |
| 10 mars | 105 | 106 | 103 | 104 | 1,300 |
| 11 mars | 104 | 107 | 103 | 106 | 1,000 |
| 12 mars | 106 | 108 | 105 | 107 | 1,400 |
| 13 mars | 107 | 109 | 106 | 108 | 1,200 |
| 14 mars | 108 | 110 | 106 | 107 | 1,600 |
Le rééchantillonnage donne deux lignes. Semaine se terminant le 7 mars : ouverture = première ouverture = 100 ; plus haut = max(102, 104, 104, 105, 106) = 106 ; plus bas = min(99, 100, 101, 101, 103) = 99 ; clôture = dernière clôture = 105 ; volume = 1,000 + 1,200 + 900 + 1,100 + 1,500 = 5,700. Semaine se terminant le 14 mars : ouverture 105, plus haut 110, plus bas 103, clôture 107, volume = 1,300 + 1,000 + 1,400 + 1,200 + 1,600 = 6,500.
Filtrage : (df["close"] > df["open"]).sum() renvoie 7, car seuls les 5, 10 et 14 mars ont clôturé sous leur ouverture. df.loc["2025-03-05":"2025-03-07", "close"] renvoie 102, 104, 105.
Erreur fréquente
df.iloc[0:5] renvoie cinq lignes (positions 0 à 4), mais df.loc["2025-03-03":"2025-03-07"] renvoie toutes les lignes jusqu'au 7 mars inclus. Utilisez iloc pour « les N premières » ou « la dernière barre », et loc avec des dates explicites pour des périodes.Exercice pratique
À partir du tableau de dix barres ci-dessus et sur papier : (a) écrivez l'expression pandas qui sélectionne les barres du 10 au 12 mars inclus ; (b) indiquez ce que renvoie df.iloc[-3:]["close"].tolist() ; (c) calculez l'unique barre mensuelle que produirait df.resample("ME").agg(rules) ; (d) expliquez ce qui ne va pas si quelqu'un écrit df.resample("ME").last() pour toutes les colonnes.
Afficher la solution
(a) df.loc["2025-03-10":"2025-03-12"], trois lignes, les deux bornes incluses.
(b) Les trois dernières clôtures : [107, 108, 107].
(c) Une ligne étiquetée 31 mars 2025 (fin de mois) : ouverture 100 (première), plus haut 110 (max), plus bas 99 (min), clôture 107 (dernière), volume 12,200 (5,700 + 6,500).
(d) .last() prend la dernière valeur de chaque colonne : le plus bas mensuel serait 106 au lieu de 99, l'ouverture 108 au lieu de 100 et le volume 1,600 au lieu de 12,200. Passez toujours les règles par colonne.
Limites : l'exemple ne comporte ni jour férié ni jour manquant ; avec des données réelles, une semaine contenant un jour férié agrège simplement quatre barres, et une étiquette mensuelle « 31 mars » apparaît même si le dernier jour de bourse était le 28 mars.
Points clés à retenir
- Les données de prix vivent dans un DataFrame doté d'un DatetimeIndex ; vérifiez
df.index.dtypeavant toute chose. locsélectionne par étiquette et inclut la fin du découpage ;ilocsélectionne par position et l'exclut.- Les masques booléens combinés avec
&,|et~remplacent les boucles pour filtrer, et.sum()sur un masque compte les correspondances. - Rééchantillonnez les OHLCV avec first/max/min/last/sum, utilisez les alias
"W-FRI"et"ME", et pensez au Copy-on-Write de pandas 3.0 lors des affectations.
Étape suivante
La leçon 4 introduit des données réelles : lecture de fichiers CSV et d'API gratuites, compréhension des prix ajustés et non ajustés, et gestion des valeurs manquantes et des fuseaux horaires.
Auto-évaluation
Répondez aux questions, puis vérifiez vos réponses. Vous pouvez recommencer autant de fois que vous le souhaitez.
Auto-évaluation automatique pour vos propres révisions. Vos réponses sont vérifiées dans votre navigateur ; nous ne les voyons pas et ne les évaluons pas. Ce n'est ni un examen ni une qualification.
Votre progression
« Terminée » signifie seulement que vous avez marqué la leçon comme lue. Ce n'est pas un test de votre compréhension. La progression et les notes sont enregistrées uniquement dans ce navigateur, sur cet appareil — pas dans un compte.