Skip to main content
v2026.11,858 entries · CC-BY 4.0
LAC HealthMedical & Research SuppliesReagents, PPE & instruments — chain-of-custody documented.Fast, traceable sourcing built for regulated research environments, from bench consumables to instrumentation.Shop lac.us CodeCASRAIlac.us

pandas rolling(): Window, min_periods and Time-Based Windows

How pandas rolling() works: window types, min_periods, center, closed, time offsets and forward windows, with checked outputs and alternatives.

Written and maintained by CASRAI Editorial Board

Last updated

Short answer: DataFrame.rolling() (and Series.rolling()) in pandas slides a fixed-size or time-based window along your data and lets you apply an aggregation such as mean(), sum() or std() to each window position. This guide is for researchers and analysts who need to smooth a measurement series, compute a moving statistic or build a time-aware feature, and who want to know exactly why the first rows come back as NaN, what min_periods, center and closed change, and how to handle irregular timestamps. Behaviour below follows the pandas 3.1.1 documentation (read 2026-11-07) and was run on pandas 3.0.5.

What pandas rolling is used for in research

A rolling calculation produces one output value per input row, computed from the rows inside a moving window. Typical research uses are smoothing a noisy instrument signal, tracking a moving mean or standard deviation of a repeated measurement, computing a moving correlation between two series, and building lagged summary features for time-series models. It is the pandas counterpart of the idea explained in what a moving average is; the same concept in another environment is covered in moving averages in MATLAB.

Rolling windows are one of three window types in the pandas windowing guide. rolling() gives every observation in the window equal weight (unless you pass win_type), expanding() grows the window from the first observation, and ewm() weights observations with exponentially decaying weights and has no window size at all.

Install or access

pandas is installed from the official project sources. According to the pandas installation page (read 2026-11-07):

  • pip install pandas (PyPI)
  • conda install -c conda-forge pandas (conda-forge), or create a fresh environment with conda create -c conda-forge -n name_of_my_env python pandas

The page lists NumPy 2.0.2 as the minimum required NumPy version. Check your installed version with pandas.__version__ before comparing outputs with the documentation.

Step-by-step: build a rolling calculation

1. The signature

The documented signature is DataFrame.rolling(window, min_periods=None, center=False, win_type=None, on=None, closed=None, step=None, method='single'). It returns a Rolling object (or a Window object when win_type is passed). Nothing is computed until you call an aggregation on it.

2. Choose the window

window can be an integer (number of observations), a time offset such as '2D' or '3s' (variable-size window, datetime-like index only, and the offset must be a fixed frequency), or a subclass of BaseIndexer for custom windows.

import pandas as pd

s = pd.Series(
    [4.0, 6.0, 5.0, 9.0, 7.0, 8.0],
    index=pd.to_datetime(["2026-01-01", "2026-01-02", "2026-01-03",
                          "2026-01-06", "2026-01-07", "2026-01-08"]),
    name="x",
)
s.rolling(3).mean()

3. Apply an aggregation

Call mean(), sum(), median(), min(), max(), std() or var(), or several at once with agg(["mean", "std"]). For anything else use apply(func, raw=...): raw=True passes each window as an ndarray, raw=False passes a Series, and engine='numba' requires raw=True. Results are float64, and the aggregations apply to numeric data. For two series, cov() and corr() give rolling covariance and correlation (with pairwise=True for all column pairs).

4. Decide how to handle the edges and missing values

Set min_periods, center and closed as described in the decision table below.

Parameter decision table

Every row below comes from the pandas DataFrame.rolling documentation (pandas 3.1.1, read 2026-11-07).

Parameter Default What it does
window required Integer = number of observations. Offset string or timedelta = variable-size time window (datetime-like index, fixed frequency only). BaseIndexer subclass = custom window.
min_periods None Minimum observations needed to produce a value. For an integer window it defaults to the window size; for an offset window it defaults to 1.
center False False labels the result at the right edge of the window; True labels it at the window centre.
win_type None None gives equal weights. A string names a valid scipy.signal window (for example "gaussian", which needs a parameter such as std in the aggregation: df.rolling(2, win_type="gaussian").sum(std=3)).
on None Column label to roll over instead of the index.
closed None (acts as 'right') Which window endpoints are included: 'right', 'left', 'both' or 'neither'.
step None Evaluate every n-th row, like slicing with [::step]. The window must be an integer.
method 'single' 'table' applies the function to the whole table and is available only with engine='numba'.

Output and how to read it

Why are the first rows NaN?

With an integer window and the default min_periods, a value is produced only when the window is full. s.rolling(3).mean() on the series above returns NaN, NaN, 5.0, 6.667, 7.0, 8.0: the first two rows have fewer than three observations. Setting min_periods=1 returns a value from the first row using whatever observations are available. The documentation example df = pd.DataFrame({"B": [0, 1, 2, np.nan, 4]}) shows the effect: df.rolling(2).sum() gives NaN, 1.0, 3.0, NaN, NaN, while df.rolling(2, min_periods=1).sum() gives 0.0, 1.0, 3.0, 2.0, 4.0.

What happens to missing data inside the window?

NaN values are not filled. They are excluded from the count of observations in the window, and min_periods decides whether the remaining observations are enough. In the example above, the NaN at position 3 makes rolling(2).sum() return NaN for that row and the next, because neither window holds two valid values; with min_periods=1 each of those windows sums its one valid value.

What does center do?

By default the result is labelled at the right edge of the window, so it describes the past. With center=True the label is the window centre. In the documentation example, df.rolling(3, min_periods=1, center=True).sum() gives 1.0, 3.0, 3.0, 6.0, 4.0 while center=False gives 0.0, 1.0, 3.0, 3.0, 6.0. On the worked series, s.rolling(3, center=True).mean() returns NaN in both the first and last rows, because an edge window of three centred values is incomplete at each end.

Time-based windows on irregular timestamps

Research data is often measured at uneven times. An offset window counts time, not rows. On the worked series (note the gap between 3 and 6 January), s.rolling("3D").mean() returns 4.0, 5.0, 5.0, 9.0, 8.0, 8.0: on 6 January the 3-day window contains only that day’s value, so the mean is 9.0. By default offset windows use min_periods=1, so no leading NaN appears. The time index must be monotonic.

Offset windows must be fixed frequencies. Calendar offsets such as 'B' (business day) or 'ME' (month end) raise a ValueError; in the version tested, the message reads that the offset “is a non-fixed frequency”. Use a fixed span such as '30D' instead.

To roll over a datetime column rather than the index, pass on: df.rolling("2D", on="A").sum().

Avoiding look-ahead with closed

For prediction features, the current row should not contribute to its own window. The pandas windowing guide notes that closed='left' or 'neither' helps avoid look-ahead. On the worked series, s.rolling("3D", closed="left").mean() returns NaN, 4.0, 5.0, 5.0, 9.0, 8.0: each value summarises only earlier observations.

Forward-looking windows

A rolling window looks backward by default. For a forward-looking window use an indexer: indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=2) followed by df.rolling(window=indexer, min_periods=1).sum(), which on the documentation example gives 1.0, 3.0, 2.0, 4.0, 4.0. A negative offset string does not create a forward window. For time-based forward windows the documentation reverses the data, rolls, then reverses back: df_time.iloc[::-1].rolling("3s").sum().iloc[::-1].

Rolling vs expanding vs ewm

rolling() expanding() ewm()
Window Fixed size or time span Grows from the first observation No window size
Weights Equal (or a scipy window via win_type) Equal Exponentially decaying; set exactly one of alpha, span, com or halflife
On the worked series, mean NaN, NaN, 5.0, 6.667, 7.0, 8.0 (window 3) 4.0, 5.0, 5.0, 6.0, 6.2, 6.5 4.0, 5.333, 5.143, 7.2, 7.097, 7.556 (span=3)

For irregular sampling, ewm accepts a times argument that works with halflife. For more on a statistical-modelling alternative to hand-built smoothing, see the statsmodels API guide.

Troubleshooting

  • Result is all NaN: the window is larger than the number of valid observations. Reduce window or set min_periods.
  • ValueError about a non-fixed frequency: you passed 'B', 'ME' or a similar calendar offset. Use a fixed span in days, hours or seconds.
  • Time-window error on an unsorted index: offset windows need a monotonic datetime index. Sort the index first.
  • Step with an offset window: step requires an integer window.
  • Gaussian window complaint: win_type="gaussian" needs std passed to the aggregation.
  • Combining datasets before rolling: align and join the series first; see pandas concat.

Free alternatives

Tool Equivalent Notes (from the tool’s own documentation)
Polars (Python) Expr.rolling_mean(window_size, weights=None, *, min_samples=None, center=False) Window length is counted in elements; min_samples defaults to the window size.
R, zoo package rollapply(data, width, FUN, ..., by = 1, fill, partial = FALSE, align = c("center", "left", "right")) Default alignment is centred; rollmean is documented as an optimised variant for means.
NumPy numpy.lib.stride_tricks.sliding_window_view Returns a view of all windows; apply a reduction along the last axis, for example .mean(axis=1). It has no NaN padding or time-based windows.

Note the different defaults: pandas labels at the right edge unless center=True, whereas zoo defaults to centred alignment. Check this when comparing results across tools. For interpolation of gaps before smoothing, see interpolation in NumPy.

FAQ

What does pandas rolling mean?

It means a moving window over the data: for each row, pandas takes the observations in a window ending at (or centred on) that row and applies a function to them.

How do I compute a rolling mean in pandas?

Call df["col"].rolling(window).mean(), for example s.rolling(3).mean(). Add min_periods=1 to avoid leading NaN rows.

How do I get a rolling max or rolling difference?

Use rolling(3).max() for the maximum (on the worked series: NaN, NaN, 6.0, 9.0, 9.0, 9.0). For the change across each window, use apply: s.rolling(3).apply(lambda w: w.iloc[-1] - w.iloc[0], raw=False) returns NaN, NaN, 1.0, 3.0, 2.0, -1.0. For a plain row-to-row difference, diff() does not need a window.

How do I get the rolling last value?

Use apply with raw=True, for example s.rolling(3).apply(lambda w: w[-1], raw=True), which passes each window as an ndarray.

How is rolling different from ewm?

Rolling weights every observation in a fixed window equally; ewm weights all earlier observations with exponentially decaying weights and has no window size.

Can pandas rolling look forward?

Yes, with FixedForwardWindowIndexer or by reversing the data; negative offset strings do not work.

Sources

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about pandas rolling(): Window, min_periods and Time-Based Windows

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →