Python
NumPy
SciPy
Rolling Average
Moving Average

How can I calculate a rolling / moving average using Python NumPy / SciPy?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A rolling or moving average smooths a sequence by replacing each position with the average of values in a nearby window. In Python, the most common NumPy solutions use cumulative sums or convolution, while SciPy offers convenient filters for the same idea. The best method depends on whether you care most about speed, edge handling, or keeping the output aligned with the original series length.

Use np.convolve for a Simple Moving Average

For many cases, convolution is the cleanest approach. A simple moving average is just convolution with a flat kernel whose values sum to 1.

python
1import numpy as np
2
3x = np.array([1, 2, 3, 4, 5], dtype=float)
4window = 3
5kernel = np.ones(window) / window
6
7avg = np.convolve(x, kernel, mode="valid")
8print(avg)

With mode="valid", only positions where the full window fits are returned. That is why the output is shorter than the input.

This is often the best answer when someone wants a concise moving average over a one-dimensional array and is comfortable with a shorter result.

Use np.cumsum When You Want Efficient Sliding Sums

A cumulative-sum approach is also common and can be very efficient for large arrays.

python
1import numpy as np
2
3x = np.array([1, 2, 3, 4, 5], dtype=float)
4window = 3
5cumsum = np.cumsum(np.insert(x, 0, 0.0))
6avg = (cumsum[window:] - cumsum[:-window]) / window
7
8print(avg)

The idea is simple: once you know cumulative sums, the sum of any fixed-width window can be obtained by subtraction. That avoids recomputing each window sum from scratch.

This method is especially useful when you want to understand the mechanics of the rolling average rather than only call a black-box function.

Keep the Output Length with Padding or same Mode

Sometimes you want one result per input element. In that case, you need to decide how to handle the edges where a full centered window is not available.

A quick approach is mode="same".

python
1import numpy as np
2
3x = np.array([1, 2, 3, 4, 5], dtype=float)
4kernel = np.ones(3) / 3
5avg = np.convolve(x, kernel, mode="same")
6
7print(avg)

This keeps the output length equal to the input length, but the boundary behavior is determined by how convolution pads the missing values. That may or may not match the semantics you want.

So the real question is not only “how do I compute the average”. It is “what should happen at the edges”.

SciPy Gives You More Control Over Edge Handling

SciPy’s filtering utilities are convenient when you want smoothing plus explicit control over boundary rules.

python
1import numpy as np
2from scipy.ndimage import uniform_filter1d
3
4x = np.array([1, 2, 3, 4, 5], dtype=float)
5avg = uniform_filter1d(x, size=3, mode="nearest")
6
7print(avg)

The mode argument controls what values are assumed beyond the boundaries. For example, nearest extends the edge value outward. Other modes give different behavior.

This is often more expressive than trying to reverse-engineer what a specific convolution padding choice means for the first and last few elements.

Choose the Window Based on the Signal

The implementation is only part of the problem. The window size determines how aggressively you smooth the series.

  • a small window preserves short-term variation,
  • a large window emphasizes long-term trends,
  • and a centered window behaves differently from a trailing window used in time-series reporting.

If the rolling average is used for analytics dashboards or finance-style reporting, make sure the window definition matches the business meaning. A mathematically correct average with the wrong window semantics is still the wrong answer.

Missing Values Need a Policy

Pure NumPy approaches will happily propagate NaN values unless you handle them explicitly. If the data can contain missing entries, decide whether you want to ignore them, fill them, or let them invalidate each window.

That decision changes the implementation. There is no single universally correct rule.

Common Pitfalls

  • Using mode="same" without understanding the implied edge behavior.
  • Expecting a centered moving average when the code actually computes a trailing one.
  • Forgetting that valid mode shortens the output array.
  • Choosing a window size based only on aesthetics rather than the meaning of the signal.
  • Ignoring NaN handling when the input data is incomplete.

Summary

  • In NumPy, moving averages are commonly computed with convolution or cumulative sums.
  • 'np.convolve is concise, while np.cumsum exposes the sliding-sum logic directly.'
  • SciPy filters such as uniform_filter1d are useful when edge handling matters.
  • Output alignment and boundary behavior are part of the problem, not an afterthought.
  • The right window size depends on the analysis goal, not only on implementation convenience.

Course illustration
Course illustration

All Rights Reserved.