拡張ウィンドウ
expanding().sum()を使い、開始位置から各時点までのすべての行を含む累積統計量を計算します。
「拡張ウィンドウ」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
What Is an Expanding Window?
An expanding window includes all rows from the very beginning of the Series up to the current row — the window grows with each new row rather than staying fixed. At row 0 it contains only one value; at row 5 it contains six values; at row 100 it contains 101 values. Expanding windows are used to compute cumulative statistics that represent the running total, running average, or running maximum from the start of the dataset to the current point in time.
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)The expanding() Method
Series.expanding(min_periods=1) returns an Expanding object. The min_periods parameter (default 1) sets the minimum number of observations required for the first non-NaN result. Unlike rolling(n), the window in expanding() is not fixed — it always starts at the beginning. Chain any aggregation: .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)Pandas cumsum, cumprod, cummax, cummin
For the most common cumulative statistics, Pandas provides direct methods on Series and DataFrame without needing expanding(): cumsum(), cumprod(), cummax(), and cummin(). These are optimised implementations that are slightly faster than their expanding() equivalents. Use these shortcuts for typical business metrics like year-to-date revenue (cumsum) or all-time maximum price (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))Year-to-Date Calculation with Expanding
A classic use of expanding windows is year-to-date (YTD) revenue. For each day, you want the sum of all revenue from January 1st of the current year up to that day. This is just cumsum() applied within each year group. Implement it with groupby(year).cumsum() — the cumsum resets at the start of each calendar year while accumulating through the year.
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))Expanding Window Standard Deviation
expanding().std() computes the running standard deviation using all data from the start to the current row. This is useful for monitoring whether the variability of a metric is increasing or decreasing over time — for example, tracking whether a product's daily sales are becoming more or less predictable as the business matures. Unlike rolling std (which only reflects recent variability), expanding std captures the full historical dispersion.
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))Comparing Rolling vs Expanding
The key distinction: rolling windows reflect recent performance (last n days) and are insensitive to long-ago data, while expanding windows incorporate all history and thus converge slowly toward stable values. Use rolling when you care about recent trends (a 7-day moving average is more responsive to recent changes than a 90-day one). Use expanding when you want all-time statistics or YTD metrics that must never forget earlier data.
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()Expanding Apply for Custom Cumulative Stats
expanding().apply(func) applies a custom function to all data from the start to the current row, just like rolling().apply(). This enables cumulative statistics not available as built-ins — for example, the cumulative coefficient of variation (std/mean), the running median, or a cumulative Sharpe ratio. The function receives a NumPy array of all values seen so far and must return a scalar.
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))Expanding Windows with NaN Handling
Expanding windows skip NaN values by default — a NaN in the middle of the Series is ignored when computing the cumulative sum or mean. You can check this with skipna=True (the default in most Pandas aggregations). When you have time series with genuine missing values (e.g. no trading on weekends), expanding statistics will be computed only from the non-NaN values seen so far, which is usually the desired behaviour.
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.')Expanding Windows for Running Benchmarks
Expanding windows are ideal for computing running benchmarks: the all-time maximum, the best-quarter-ever, or the lowest error rate since launch. These KPIs require remembering all historical values — a rolling window would forget old records. Using cummax() or cummin() returns the running best (or worst) at each point, making it easy to track when new records were set.
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'))Practical Example: Cumulative Returns
In finance, cumulative returns show how much an investment has grown from the start date to each subsequent date. Starting from daily percentage returns, the cumulative product of (1 + daily_return) gives the total growth factor. An expanding product is more natural than a rolling product here — you want to track total growth since inception, not just over the last n days.
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}%')When to Use Expanding vs Rolling vs cumsum
Guidelines for choosing the right approach:
- Use
cumsum() / cummax() / cummin()for simple cumulative aggregations — they are the fastest option. - Use
expanding().mean() / std()when you need cumulative running averages or variance. - Use
expanding().apply(custom_func)for complex all-time statistics not available as built-ins. - Use
rolling(n)instead of expanding when only recent history should influence the current value.
Quick Check
Test your understanding of expanding windows from this lesson.
Lesson Recap
In this lesson you learned: expanding() computes cumulative statistics over a growing window from the start of the Series, cumsum/cummax/cummin are optimised shortcuts for common cumulative operations, and expanding windows are ideal for all-time records, YTD metrics, and cumulative investment returns. Next up we explore exponentially weighted moving averages (EWMA) — giving more weight to recent observations.
よくある質問
「拡張ウィンドウ」レッスンは無料ですか?
はい。「拡張ウィンドウ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
「拡張ウィンドウ」で何を学びますか?
expanding().sum()を使い、開始位置から各時点までのすべての行を含む累積統計量を計算します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Pandas & NumPy Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「拡張ウィンドウ」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPandas & NumPy Academyレッスンでコードを書いて実行できますか?
はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。