Skip to content

Resampling and Frequency Conversion

What resampling means

Resampling converts a time series from one frequency to another:

  • Downsampling — high frequency → low frequency (minute data → daily totals). This always needs an aggregation, because many points collapse into one bucket.
  • Upsampling — low frequency → high frequency (weekly data → daily rows). This creates new rows, which start out empty unless you fill them.

.resample().resample() has a similar API to .groupby().groupby(): call resample()resample() to define the buckets, then call an aggregation like .sum().sum() or .mean().mean().

Downsampling: many points into one bucket

Minute data into 5-minute buckets
import pandas as pd
 
idx = pd.date_range("2024-01-01", periods=12, freq="min")
ts = pd.Series(range(12), index=idx)
 
print(ts.resample("5min").sum())
Minute data into 5-minute buckets
import pandas as pd
 
idx = pd.date_range("2024-01-01", periods=12, freq="min")
ts = pd.Series(range(12), index=idx)
 
print(ts.resample("5min").sum())

Two choices control how buckets are formed:

  • closedclosed — which edge of each interval is inclusive ("left""left" or "right""right").
  • labellabel — whether the result is labeled with the left or right edge.
closed and label options
print(ts.resample("5min", closed="right").sum())
print(ts.resample("5min", closed="right", label="right").sum())
closed and label options
print(ts.resample("5min", closed="right").sum())
print(ts.resample("5min", closed="right", label="right").sum())

OHLC: a finance-flavored aggregation

For price data, a common summary per bucket is open, high, low, close — computed in one call:

OHLC resampling
print(ts.resample("5min").ohlc())
OHLC resampling
print(ts.resample("5min").ohlc())

Upsampling: creating new rows

Going from weekly to daily creates rows that don’t exist yet — they start as NaNNaN unless you tell pandas how to fill them:

Upsampling with asfreq vs ffill
weekly = pd.DataFrame(
    {"a": [1, 2]},
    index=pd.date_range("2024-01-03", periods=2, freq="W-WED"),
)
 
print(weekly.resample("D").asfreq())  # new rows are NaN
print(weekly.resample("D").ffill())   # new rows carry the last known value forward
Upsampling with asfreq vs ffill
weekly = pd.DataFrame(
    {"a": [1, 2]},
    index=pd.date_range("2024-01-03", periods=2, freq="W-WED"),
)
 
print(weekly.resample("D").asfreq())  # new rows are NaN
print(weekly.resample("D").ffill())   # new rows carry the last known value forward

resample vs groupby

Both split data into buckets and apply a function — the difference is what defines a bucket:

  • groupby("column")groupby("column") groups by the values in a column.
  • resample("2D")resample("2D") groups by fixed time intervals, regardless of how many rows fall into each one.
A resample call, side by side with what groupby does
sales = pd.DataFrame(
    {"amount": [10, 20, 30, 40, 50]},
    index=pd.date_range("2024-01-01", periods=5, freq="D"),
)
 
print(sales.resample("2D").sum())
A resample call, side by side with what groupby does
sales = pd.DataFrame(
    {"amount": [10, 20, 30, 40, 50]},
    index=pd.date_range("2024-01-01", periods=5, freq="D"),
)
 
print(sales.resample("2D").sum())

Common pitfalls

  • Downsampling needs an aggregation (.sum().sum(), .mean().mean(), .ohlc().ohlc(), …); calling .resample("5min").resample("5min") alone just returns a lazy resampler object, not data.
  • The default for closedclosed/labellabel is "left""left" for most frequencies but "right""right" for a handful ("ME""ME", "YE""YE", "QE""QE", "W""W") — always check the output on real data.
  • Upsampling with .asfreq().asfreq() introduces NaNNaN; you must explicitly choose .ffill().ffill() or another fill strategy if you don’t want gaps.

Visualize it

diagram Downsampling vs upsampling mermaid
Downsampling aggregates many high-frequency points into fewer buckets; upsampling creates new, empty rows that need an explicit fill strategy.
sketch High-frequency points collapsing into buckets p5.js
Twelve minute-level points (amber) are grouped by resample into three 5-minute buckets, each collapsed to one summary bar (blue).

🧪 Try It Yourself

Exercise 1 – Downsample Minute Data to 5-Minute Sums

Exercise 2 – Upsample and Forward-Fill

Exercise 3 – Compute OHLC in One Call

Next

Resampling collapses data into buckets. Rolling and Moving Window Functions instead slides a window across the data without collapsing rows — great for smoothing noisy series.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did