Why moving windows matter
Real time series are noisy — daily sales bounce around, stock prices jitter minute to minute. A moving window function recomputes a statistic (mean, std, ...) over a small sliding slice of the data, smoothing out that noise so the underlying trend is easier to see.
Pandas gives you three flavors:
.rolling(window)— a fixed-size window that slides forward..expanding()— a window that starts small and grows to include everything seen so far..ewm(span=...)— an exponentially weighted window that favors recent observations.
Rolling mean and std
import pandas as pd
s = pd.Series(
[10, 12, 13, 12, 15, 20, 18, 22, 25, 30],
index=pd.date_range("2024-01-01", periods=10, freq="D"),
)
print(s.rolling(3).mean()) # 3-day moving averagerolling(3) behaves like groupby, but instead of grouping by a key, it creates a
sliding 3-row window. Notice the first two values are NaN — there aren't 3 rows yet
to average.
min_periods: dealing with a short warm-up
By default, a rolling window needs every slot filled before it produces a value.
min_periods relaxes that, useful right at the start of a series:
print(s.rolling(3, min_periods=1).mean()) # no leading NaN this timeExpanding windows
An expanding window is like a rolling window whose size keeps growing — it always starts at the beginning of the series and includes everything up to the current row:
print(s.expanding().mean()) # cumulative average up to each pointExponentially weighted windows (ewm)
Instead of weighting every value in the window equally, ewm gives more weight to
recent observations — it "reacts" faster to a change than a simple moving average:
print(s.ewm(span=3).mean())Rolling correlation (two series at once)
Some window functions — like correlation — need two series. Calling .rolling(...)
on one series and then .corr(other) computes a rolling correlation between them:
bench = pd.Series(
[1, 1.2, 1.1, 1.3, 1.5, 1.6, 1.4, 1.7, 1.9, 2.0],
index=s.index,
)
rolling_corr = s.pct_change().rolling(4, min_periods=2).corr(bench.pct_change())
print(rolling_corr)Common pitfalls
- Without
min_periods, the firstwindow - 1rows of a rolling result are alwaysNaN. - Rolling window functions automatically skip missing data, but they still require
min_periodsvalid values to produce output. ewmdoesn't have a fixed "window size" the wayrollingdoes —spanjust controls how quickly old observations lose influence.
Visualize it
flowchart LR A["Raw noisy series"] --> B["rolling(3).mean()
fixed-size sliding window"] A --> C["expanding().mean()
grows from the start"] A --> D["ewm(span=3).mean()
recent points weighted more"] B --> E["Smoothed line"] C --> E D --> E
🧪 Try It Yourself
Exercise 1 – Compute a Rolling Mean
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 2 – Avoid Leading NaN With min_periods
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 3 – Compute an Expanding Mean
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Check your understanding
What does s.rolling(3).mean() return for the first two rows?
A window of 3 needs 3 rows before it can produce a value, so the first window - 1 rows are NaN.
Show answer
A — NaN — A window of 3 needs 3 rows before it can produce a value, so the first window - 1 rows are NaN.
What does min_periods=1 change in s.rolling(3, min_periods=1).mean()?
min_periods relaxes the requirement that every slot be filled, which is useful at the start of a series.
Show answer
A — It removes the leading NaN by allowing a shorter warm-up window — min_periods relaxes the requirement that every slot be filled, which is useful at the start of a series.
How does expanding().mean() differ from rolling(3).mean()?
An expanding window starts at the beginning and keeps growing, giving a cumulative average.
Show answer
A — Expanding includes everything from the start up to the current row — An expanding window starts at the beginning and keeps growing, giving a cumulative average.
What does ewm(span=3) do differently from a simple moving average?
The exponentially weighted mean reacts faster to changes. It has no fixed window size, and span controls how quickly old values lose influence.
Show answer
A — It gives more weight to recent observations — The exponentially weighted mean reacts faster to changes. It has no fixed window size, and span controls how quickly old values lose influence.
Next
That completes the Pandas phase. Head into Phase 4 — Data Preprocessing and Cleaning, starting with Understanding Data Quality, to apply these skills to real, messier datasets.