API · Pandas
Pandas DataFrame.rolling() Function
The DataFrame rolling() function provides a rolling window for mathematical operations.
On this page
Python Pandas DataFrame.rolling() provides a rolling window for mathematical operations. Calling rolling() alone computes nothing: it returns a Rolling object that defines the moving windows, and an aggregation method such as sum(), mean(), or std() then reduces each window to one row of results. Because a window normally ends at the current row, the result keeps the same index as the original DataFrame, which makes rolling() the standard way to build trailing sums, moving averages, and other running statistics.
Syntax of pandas.DataFrame.rolling()
DataFrame.rolling(
window, min_periods=None, center=False, win_type=None, on=None,
closed=None, step=None, method='single'
)
Parameters
window |
It is an integer, offset, or BaseIndexer subclass. It specifies the size of the moving window: a fixed number of observations, or a time span such as '3D' when an offset is used. |
min_periods |
It is an integer parameter. It specifies the minimum number of observations in a window that are not NaN; windows with fewer observations return NaN. When it is not set, it defaults to the window size for fixed windows and to 1 for time-based windows. |
center |
It is a Boolean parameter. When it is True, each result is labelled at the center of its window instead of at the right edge. |
win_type |
It is a string parameter. It specifies a weighted window type such as 'triang', so observations inside the window contribute with different weights. Most weighted window types require SciPy. |
on |
It is a string parameter. It specifies the column name to calculate the rolling window on, instead of the index; it is used with time-based windows when the dates are stored in a column. |
closed |
It is a string parameter. It specifies which side of the window interval is closed. It has four options: right, left, both, or neither. The default is right. |
step |
It is an integer parameter. The window is evaluated only at every step rows, so the result contains just those rows. |
Return
It returns a Rolling window object. Calling an aggregation method on it returns a DataFrame with the same index as the input.
The signature above is the current one. The axis parameter that older tutorials show no longer exists, because a rolling window always moves along the index; passing it raises a TypeError, as shown in the error section below.
Example: Rolling Sum With a Fixed Window of 2
The most common form uses an integer window that counts rows. In this example, rolling(2).sum() adds every row to the row directly above it.
import pandas as pd
dataframe = pd.DataFrame({
'Attendance': {0: 60, 1: 100, 2: 80, 3: 78, 4: 95},
'Obtained Marks': {0: 90, 1: 75, 2: 82, 3: 64, 4: 45},
})
print("The Original DataFrame is:")
print(dataframe)
print("The Rolling Sum With a Window of 2 is:")
print(dataframe.rolling(2).sum())
Output:
The Original DataFrame is:
Attendance Obtained Marks
0 60 90
1 100 75
2 80 82
3 78 64
4 95 45
The Rolling Sum With a Window of 2 is:
Attendance Obtained Marks
0 NaN NaN
1 160.0 165.0
2 180.0 157.0
3 158.0 146.0
4 173.0 109.0
Row 0 has no row above it, so its window holds a single observation — fewer than the two that the default min_periods requires — and the result is NaN. From row 1 onward, each value is the sum of the current and the previous row: 60 + 100 = 160, 100 + 80 = 180, and so on. The integer columns become floats because of that first NaN.
Example: Rolling Mean and min_periods
The same window works with any aggregation. Here, rolling(3).mean() averages the current row and the two rows above it. With the default min_periods, the first two rows cannot fill a three-row window and stay NaN. Setting min_periods=1 tells pandas to work with however many observations are available at the start, so the result is defined from the first row.
import pandas as pd
dataframe = pd.DataFrame({
'Attendance': {0: 60, 1: 100, 2: 80, 3: 78, 4: 95},
'Obtained Marks': {0: 90, 1: 75, 2: 82, 3: 64, 4: 45},
})
print("The Rolling Mean With a Window of 3 is:")
print(dataframe.rolling(3).mean())
print("The Rolling Mean With a Window of 3 and min_periods=1 is:")
print(dataframe.rolling(3, min_periods=1).mean())
Output:
The Rolling Mean With a Window of 3 is:
Attendance Obtained Marks
0 NaN NaN
1 NaN NaN
2 80.000000 82.333333
3 86.000000 73.666667
4 84.333333 63.666667
The Rolling Mean With a Window of 3 and min_periods=1 is:
Attendance Obtained Marks
0 60.000000 90.000000
1 80.000000 82.500000
2 80.000000 82.333333
3 86.000000 73.666667
4 84.333333 63.666667
The two outputs agree from index 2 onward. The difference is at the top: min_periods=1 additionally reports 60.00 for the first row (that value alone) and 80.00 for the second (the mean of the first two values). Note that min_periods counts the observations that are not NaN, which also makes it the main control for gaps inside the data, as the last example shows.
Example: Rolling Sum Over a Time-Based Window
window can also be a time offset such as '3D'. The window then covers a span of time instead of a fixed number of rows, so records only contribute when they fall inside the span, no matter how irregularly they are spaced. When the dates live in a column rather than in the index, name that column with on. The sales below have no records for 2026-01-04 and 2026-01-07.
import pandas as pd
sales = pd.DataFrame({
'Date': pd.to_datetime(['2026-01-01', '2026-01-02', '2026-01-03',
'2026-01-05', '2026-01-06', '2026-01-08']),
'Sales': [120, 80, 150, 90, 200, 60],
})
print(sales)
print("The Rolling Sum Over the Previous 3 Days is:")
print(sales.rolling('3D', on='Date').sum())
Output:
Date Sales
0 2026-01-01 120
1 2026-01-02 80
2 2026-01-03 150
3 2026-01-05 90
4 2026-01-06 200
5 2026-01-08 60
The Rolling Sum Over the Previous 3 Days is:
Date Sales
0 2026-01-01 120.0
1 2026-01-02 200.0
2 2026-01-03 350.0
3 2026-01-05 240.0
4 2026-01-06 290.0
5 2026-01-08 260.0
For 2026-01-05 the three-day window reaches back past 2026-01-02, so it contains the sales of 2026-01-03 and 2026-01-05 only: 150 + 90 = 240. The missing 2026-01-04 contributes nothing and does not shift the span the way an extra row would shift a fixed window. Notice that the first row already has a result: a time-based window defaults to min_periods=1, the opposite default from fixed windows.
Example: center the Labels and closed to Exclude the Current Row
Two parameters change where a result belongs. With center=True, the aggregated value is placed on the middle row of its window instead of the last one, which is what you want when a moving average should align with the data it smooths; the first and last rows lose their result, because no complete window is centered on them. closed controls which end of the interval is included: with closed='left', the window for a row covers the rows before it and the row itself is left out of its own statistic.
import pandas as pd
temps = pd.DataFrame({'Temperature': [10, 12, 14, 16, 18, 20]})
print("The Centered Rolling Mean With a Window of 3 is:")
print(temps.rolling(3, center=True).mean())
print("The Rolling Sum With a Window of 3 and closed='left' is:")
print(temps.rolling(3, closed='left').sum())
Output:
The Centered Rolling Mean With a Window of 3 is:
Temperature
0 NaN
1 12.0
2 14.0
3 16.0
4 18.0
5 NaN
The Rolling Sum With a Window of 3 and closed='left' is:
Temperature
0 NaN
1 NaN
2 NaN
3 36.0
4 42.0
5 48.0
The centered mean at index 1 is 12.0 — the mean of 10, 12, and 14 — and it sits on the middle row of that window. The closed='left' sums show the familiar 36, 42, 48 pattern shifted one row down: at index 3 the window holds rows 0 to 2 (10 + 12 + 14 = 36), because row 3 itself is excluded.
Common Errors and Boundary Cases
Three behaviors surprise users most often, and each one is visible in a small example.
Missing Values Inside the Window
Because min_periods counts the observations that are not NaN, a single missing value empties every fixed window that contains it, plus the window that follows it. Lowering min_periods makes the aggregation use the values that do exist.
import pandas as pd
scores = pd.DataFrame({'Score': [50.0, None, 70.0, 90.0]})
print(scores)
print("The Rolling Sum With a Window of 2 is:")
print(scores.rolling(2).sum())
print("The Rolling Sum With a Window of 2 and min_periods=1 is:")
print(scores.rolling(2, min_periods=1).sum())
Output:
Score
0 50.0
1 NaN
2 70.0
3 90.0
The Rolling Sum With a Window of 2 is:
Score
0 NaN
1 NaN
2 NaN
3 160.0
The Rolling Sum With a Window of 2 and min_periods=1 is:
Score
0 50.0
1 50.0
2 70.0
3 160.0
With the default settings, only the last sum, 70 + 90, survives. With min_periods=1, the window at index 2 holds one valid value, so its sum is 70: the missing entry is skipped instead of propagated. Neither behavior repairs the data — choose between them based on whether a partial window is meaningful for your statistic.
Invalid Arguments Raise ValueError
rolling() validates its arguments before anything is calculated. A negative window fails immediately:
import pandas as pd
temps = pd.DataFrame({'Temperature': [10, 12, 14, 16, 18, 20]})
print(temps.rolling(-1).sum())
Output:
ValueError: window must be an integer 0 or greater
An unknown closed value fails the same way, with ValueError: closed must be 'right', 'left', 'both' or 'neither', and a fractional window such as 2.5 is rejected with the same message as the negative window. Note that window=0 is accepted but degenerate: every window is empty, so sum() returns 0.0 for every row.
Non-Numeric Columns Raise DataError
Aggregations accept numeric data only. Rolling a DataFrame that still contains a text column raises an error:
import pandas as pd
mixed = pd.DataFrame({'Name': ['A', 'B', 'C'], 'Value': [1, 2, 3]})
print(mixed.rolling(2).sum())
Output:
pandas.errors.DataError: Cannot aggregate non-numeric type: str
Select the numeric columns before rolling — for example mixed[['Value']].rolling(2).sum() — or drop the label columns first.
Things to Keep in Mind
rolling()by itself returns aRollingobject; nothing is computed until an aggregation method is called. The result always carries the input’s index, so it can be assigned straight back as a new column.- Integer columns turn into floats as soon as a
NaNappears in the output, becauseNaNhas no integer representation. - For grouped calculations, call
rolling()on agroupbyobject, as indf.groupby('key').rolling(2).sum(): the window then restarts at every group instead of crossing group boundaries. - Weighted windows through
win_typeare meant for signal-style data; for plain business data the unweighted aggregations in the examples above are the right default.