Pandas & NumPy Academy · Leçon

Fenêtres cumulées

Calculez des statistiques cumulées incluant toutes les lignes depuis le début jusqu’à chaque point avec expanding().sum().

Leçon 2 sur 413 étapes

Fenêtres cumulées est une leçon Pandas & NumPy Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Pandas & NumPy Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Pandas & NumPy Academy comprend 4 leçons au total.

Qu’est-ce qu’une fenêtre extensible ?

Une fenêtre extensible inclut toutes les lignes depuis le tout début de la Series jusqu’à la ligne actuelle : la fenêtre s’agrandit à chaque nouvelle ligne au lieu de rester fixe. À la ligne 0, elle ne contient qu’une valeur ; à la ligne 5, elle en contient six ; à la ligne 100, elle en contient 101. Les fenêtres extensibles servent à calculer des statistiques cumulées représentant le total cumulé, la moyenne cumulée ou le maximum cumulé depuis le début du jeu de données jusqu’au moment présent.

import pandas as pd
import numpy as np

sales = pd.Series(
    [100, 150, 120, 200, 180, 160, 220, 190],
    index=pd.date_range('2024-01-01', periods=8)
)

# Expanding mean — grows with each row
df = pd.DataFrame({'sales': sales})
df['cumulative_mean'] = df['sales'].expanding().mean()
print(df)

La méthode expanding()

Series.expanding(min_periods=1) renvoie un objet Expanding. Le paramètre min_periods (1 par défaut) définit le nombre minimal d’observations nécessaires pour obtenir le premier résultat différent de NaN. Contrairement à rolling(n), la fenêtre de expanding() n’est pas fixe : elle commence toujours au début. Vous pouvez enchaîner n’importe quelle agrégation : .sum(), .mean(), .std(), .min(), .max().

import pandas as pd
import numpy as np

np.random.seed(42)
monthly_revenue = pd.Series(
    np.random.randint(500, 1500, 12),
    index=pd.date_range('2024-01', periods=12, freq='ME'),
    name='revenue'
)

df = pd.DataFrame({'revenue': monthly_revenue})
df['cumsum'] = df['revenue'].expanding().sum()
df['cummean'] = df['revenue'].expanding().mean()
df['cummax'] = df['revenue'].expanding().max()
df['cummin'] = df['revenue'].expanding().min()
print(df)

cumsum, cumprod, cummax et cummin de Pandas

Pour les statistiques cumulées les plus courantes, Pandas fournit des méthodes directes sur les Series et les DataFrame, sans nécessiter expanding() : cumsum(), cumprod(), cummax() et cummin(). Ces implémentations optimisées sont légèrement plus rapides que leurs équivalents expanding(). Utilisez ces raccourcis pour les indicateurs courants, comme le chiffre d’affaires depuis le début de l’année (cumsum) ou le prix maximal historique (cummax).

import pandas as pd
import numpy as np

prices = pd.Series(
    [100, 95, 110, 105, 120, 115, 130, 125],
    index=pd.date_range('2024-01-01', periods=8)
)

df = pd.DataFrame({'price': prices})
df['cummax'] = df['price'].cummax()    # all-time high
df['cummin'] = df['price'].cummin()    # all-time low
df['cumsum'] = df['price'].cumsum()    # cumulative total
df['cumprod'] = (1 + df['price'].pct_change()).cumprod()  # growth index
print(df.round(3))

Calcul depuis le début de l’année avec expanding

Le chiffre d’affaires depuis le début de l’année (YTD) est un cas d’utilisation classique des fenêtres extensibles. Pour chaque jour, vous voulez calculer la somme de tous les revenus depuis le 1er janvier de l’année en cours jusqu’à ce jour. Il suffit d’appliquer cumsum() à chaque groupe annuel. Implémentez cela avec groupby(year).cumsum() : le cumsum est réinitialisé au début de chaque année civile, puis s’accumule tout au long de l’année.

import pandas as pd
import numpy as np

np.random.seed(0)
dates = pd.date_range('2023-01-01', '2024-06-30', freq='ME')
daily = pd.DataFrame({
    'date': dates,
    'revenue': np.random.randint(100, 500, len(dates))
})

# Year-to-date cumulative revenue
daily['year'] = daily['date'].dt.year
daily['ytd_revenue'] = daily.groupby('year')['revenue'].cumsum()
daily = daily.drop(columns='year')
print(daily.tail(10).to_string(index=False))

Écart-type avec une fenêtre extensible

expanding().std() calcule l’écart-type cumulé à partir de toutes les données depuis le début jusqu’à la ligne actuelle. Cela permet de surveiller si la variabilité d’un indicateur augmente ou diminue au fil du temps, par exemple pour suivre si les ventes quotidiennes d’un produit deviennent plus ou moins prévisibles à mesure que l’activité mûrit. Contrairement à rolling std, qui ne reflète que la variabilité récente, expanding std prend en compte toute la dispersion historique.

import pandas as pd
import numpy as np

np.random.seed(42)
sales = pd.Series(
    np.concatenate([
        np.random.normal(100, 5, 30),   # stable period
        np.random.normal(100, 25, 30)   # volatile period
    ]),
    index=pd.date_range('2024-01-01', periods=60)
)

df = pd.DataFrame({'sales': sales})
df['expanding_std'] = df['sales'].expanding().std()
df['rolling_30d_std'] = df['sales'].rolling(30).std()
print(df.tail(10).round(2))

Comparer rolling et expanding

La distinction essentielle est la suivante : les fenêtres glissantes reflètent les performances récentes (les n derniers jours) et sont peu influencées par les données anciennes, tandis que les fenêtres extensibles intègrent tout l’historique et convergent donc lentement vers des valeurs stables. Utilisez rolling lorsque vous vous intéressez aux tendances récentes : une moyenne mobile sur 7 jours réagit davantage aux changements récents qu’une moyenne sur 90 jours. Utilisez expanding lorsque vous voulez des statistiques historiques ou des indicateurs YTD qui ne doivent jamais oublier les données antérieures.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(10)
data = pd.Series(
    np.random.randn(60).cumsum() + 50,
    index=pd.date_range('2024-01-01', periods=60)
)

df = pd.DataFrame({'value': data})
df['rolling_10'] = data.rolling(10).mean()
df['expanding'] = data.expanding().mean()

df.plot(figsize=(12, 5), title='Rolling 10-day Mean vs. Expanding Mean')
plt.ylabel('Value')
plt.show()

Apply avec expanding pour des statistiques cumulées personnalisées

expanding().apply(func) applique une fonction personnalisée à toutes les données depuis le début jusqu’à la ligne actuelle, exactement comme rolling().apply(). Cela permet de calculer des statistiques cumulées qui ne sont pas disponibles parmi les fonctions intégrées, par exemple le coefficient de variation cumulé (std/mean), la médiane cumulée ou un ratio de Sharpe cumulé. La fonction reçoit un tableau NumPy contenant toutes les valeurs observées jusqu’alors et doit renvoyer un scalaire.

import pandas as pd
import numpy as np

np.random.seed(0)
returns = pd.Series(
    np.random.normal(0.001, 0.02, 60),
    index=pd.date_range('2024-01-01', periods=60)
)

# Cumulative Sharpe ratio (mean/std of returns)
def sharpe(arr):
    if len(arr) < 2:
        return float('nan')
    return arr.mean() / arr.std() * (252 ** 0.5)  # annualised

df = pd.DataFrame({'returns': returns})
df['cum_sharpe'] = df['returns'].expanding().apply(sharpe, raw=True)
print(df.tail(8).round(4))

Fenêtres extensibles et gestion des NaN

Par défaut, les fenêtres extensibles ignorent les valeurs NaN : un NaN au milieu de la Series est ignoré lors du calcul de la somme ou de la moyenne cumulée. Vous pouvez le vérifier avec skipna=True (valeur par défaut dans la plupart des agrégations Pandas). Lorsque vos séries temporelles contiennent de vraies valeurs manquantes, par exemple en l’absence de transactions le week-end, les statistiques extensibles sont calculées uniquement à partir des valeurs non NaN observées jusqu’alors, ce qui correspond généralement au comportement souhaité.

import pandas as pd
import numpy as np

data = pd.Series([10, np.nan, 20, 30, np.nan, 40, 50])

# cumsum skips NaN by default
df = pd.DataFrame({'value': data})
df['cumsum'] = df['value'].cumsum()      # NaN propagates in cumsum!
df['expanding_sum'] = df['value'].expanding().sum()  # NaN skipped

print(df)
print('\nNote: cumsum propagates NaN; expanding().sum() skips it.')

Fenêtres extensibles pour les références cumulées

Les fenêtres extensibles sont idéales pour calculer des références cumulées : le maximum historique, le meilleur trimestre jamais réalisé ou le taux d’erreur le plus faible depuis le lancement. Ces indicateurs clés doivent conserver toutes les valeurs historiques ; une fenêtre glissante oublierait les anciens enregistrements. L’utilisation de cummax() ou cummin() renvoie la meilleure (ou la pire) valeur cumulée à chaque instant, ce qui facilite le suivi de l’établissement de nouveaux records.

import pandas as pd
import numpy as np

np.random.seed(5)
sales = pd.Series(
    np.random.randint(100, 300, 20),
    index=pd.date_range('2024-01-01', periods=20),
    name='daily_sales'
)

df = pd.DataFrame({'sales': sales})
df['all_time_max'] = df['sales'].cummax()
df['new_record'] = df['sales'] == df['all_time_max']

print('Days where a new sales record was set:')
print(df[df['new_record']].drop(columns='new_record'))

Exemple pratique : rendements cumulés

En finance, les rendements cumulés indiquent la croissance d’un investissement depuis sa date de départ jusqu’à chaque date suivante. À partir des rendements quotidiens en pourcentage, le produit cumulé de (1 + daily_return) donne le facteur de croissance total. Un produit extensible est ici plus naturel qu’un produit glissant : vous voulez suivre la croissance totale depuis le lancement, et non uniquement celle des n derniers jours.

import pandas as pd
import numpy as np

np.random.seed(7)
start_price = 100
daily_returns = pd.Series(
    np.random.normal(0.0005, 0.015, 252),
    index=pd.date_range('2024-01-01', periods=252)
)

# Cumulative return = product of (1 + r_i)
cum_returns = (1 + daily_returns).cumprod()
portfolio_value = start_price * cum_returns

print(f'Start value: ${start_price:.2f}')
print(f'End value:   ${portfolio_value.iloc[-1]:.2f}')
print(f'Total return: {(portfolio_value.iloc[-1]/start_price - 1)*100:.1f}%')

Quand utiliser expanding, rolling ou cumsum

Voici quelques recommandations pour choisir la bonne approche :

  • Utilisez cumsum() / cummax() / cummin() pour les agrégations cumulées simples : ce sont les options les plus rapides.
  • Utilisez expanding().mean() / std() lorsque vous avez besoin de moyennes ou de variances cumulées.
  • Utilisez expanding().apply(custom_func) pour les statistiques historiques complexes qui ne sont pas disponibles parmi les fonctions intégrées.
  • Utilisez rolling(n) plutôt que expanding lorsque seule l’historique récent doit influencer la valeur actuelle.

Vérification rapide

Vérifiez votre compréhension des fenêtres extensibles présentées dans cette leçon.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris que expanding() calcule des statistiques cumulées sur une fenêtre qui s’agrandit depuis le début de la Series, que cumsum/cummax/cummin sont des raccourcis optimisés pour les opérations cumulées courantes, et que les fenêtres extensibles sont idéales pour les records historiques, les indicateurs YTD et les rendements cumulés des investissements. Nous allons maintenant étudier les moyennes mobiles pondérées exponentiellement (EWMA), qui accordent davantage de poids aux observations récentes.

Gratuit pour commencer

Apprends Python avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
30
Leçons
120

Questions Fréquemment Posées

La leçon « Fenêtres cumulées » est-elle gratuite ?

Oui — le texte complet de « Fenêtres cumulées » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Pandas & NumPy Academy, passe à CoddyKit PRO. Le cours Pandas & NumPy Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Fenêtres cumulées » ?

Calculez des statistiques cumulées incluant toutes les lignes depuis le début jusqu’à chaque point avec expanding().sum(). Tu pratiques Pandas & NumPy Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Pandas & NumPy Academy ?

Aucune expérience préalable n'est requise. Pandas & NumPy Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Fenêtres cumulées » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Pandas & NumPy Academy ?

Oui. Chaque leçon Pandas & NumPy Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Fenêtres glissantes
  2. Fenêtres cumulées
  3. Moyenne mobile pondérée exponentiellement
  4. Rangs et percentiles au sein des groupes
← Retour à Pandas & NumPy Academy