0Pricing
Pandas & NumPy Academy · 강의

확장 창

expanding().sum()을 사용해 시작부터 각 지점까지의 모든 행을 포함하는 누적 통계를 계산합니다.

확장 창은(는) CoddyKit의 무료 Pandas & NumPy Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 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/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Pandas & NumPy Academy 강의 전체를 잠금 해제할 수 있습니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“확장 창”에서 뭘 배우나요?

expanding().sum()을 사용해 시작부터 각 지점까지의 모든 행을 포함하는 누적 통계를 계산합니다. 브라우저에서 직접 실행하는 실습 코드로 Pandas & NumPy Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Pandas & NumPy Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Pandas & NumPy Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“확장 창” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Pandas & NumPy Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Pandas & NumPy Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 이동 창
  2. 확장 창
  3. 지수 가중 이동 평균
  4. 그룹 내 순위와 백분위
← Pandas & NumPy Academy(으)로 돌아가기