Skip to main content
v2026.11,986 entries · CC-BY 4.0

pandas resample: Time Series Downsampling Guide

pandas resample aggregates and converts time series frequencies. Learn downsampling rules, bin edge alignment, and upsampling interpolation for research data.

Written and maintained by CASRAI Editorial Board

Published

On this page

The pandas resample method provides frequency conversion and time-bucket aggregation for time series data. In research workflows, datasets collected from physical sensors, clinical monitoring equipment, environmental logging arrays, or automated laboratory assays frequently record observations at uneven timestamps or at higher sampling rates than required for statistical modeling. Using resample pandas workflows allows analysts to downsample high-frequency measurements into standardized intervals or upsample low-frequency data to align multiple instruments onto a shared temporal grid.

What it is used for in research

In observational and experimental research, time series datasets often present irregular intervals, variable sampling rates across instruments, or sensor noise that obscures underlying trends. The DataFrame.resample() and Series.resample() methods serve several core functions in research data preparation:

  • Downsampling and Aggregation: Condensing high-frequency continuous telemetry (such as 10 Hz accelerometer readings or 1-minute weather station logs) into hourly, daily, or weekly summaries using statistical estimators such as mean, standard deviation, median, or interquartile ranges.
  • Temporal Standardization: Aligning asynchronous measurements from disparate instruments onto uniform time buckets so multi-stream data can be merged and analyzed jointly.
  • Upsampling and Gap Imputation: Expanding low-frequency records (such as weekly laboratory specimen counts or monthly field surveys) onto daily grids using forward-filling, backward-filling, or linear interpolation.
  • Multi-Variable Summaries: Applying composite aggregations across complex data structures, such as calculating simultaneous minimum, maximum, mean, and sample counts across experimental channels.

Resampling requires the target DataFrame or Series to have a datetime-like index (such as a DatetimeIndex, TimedeltaIndex, or PeriodIndex) or to specify a datetime column directly using the on parameter. For related details on preparing timestamp columns and validating data structures, refer to the guides on pandas datetime parsing and pandas dtypes management.

Install or access (official source only)

The pandas library is open-source software distributed under the BSD 3-Clause License. It can be installed into research environments directly through official Python package repositories:

  • PyPI (Python Package Index):
    pip install pandas
  • Conda (conda-forge channel):
    conda install -c conda-forge pandas

Official pandas releases require Python 3.10 or higher. Researchers can verify the installed version and import the package in an interactive shell or script:

import pandas as pd
print(pd.__version__)

Step-by-step task (numbered, with menu names or commands exactly as in the current docs)

The following five-step task demonstrates how to construct a research time series, downsample it to regular intervals, control bin boundary behaviors, upsample with interpolation, and resample directly on a DataFrame column without resetting the index.

Step 1: Construct a sample research time series with DatetimeIndex

Generate a sample environmental monitoring dataset with 10-minute intervals over a 24-hour observation window:

import pandas as pd
import numpy as np

# Create datetime index spanning 24 hours at 10-minute intervals
timestamps = pd.date_range(start="2026-05-01 00:00:00", periods=144, freq="10min")

# Generate synthetic sensor data for temperature and relative humidity
np.random.seed(42)
df_sensor = pd.DataFrame({
    "temperature_c": np.random.normal(loc=21.5, scale=1.2, size=144),
    "humidity_pct": np.random.normal(loc=55.0, scale=3.5, size=144)
}, index=timestamps)

print(df_sensor.head(3))

Step 2: Downsample observations using modern offset aliases

To reduce 10-minute sensor data to 1-hour summary statistics, pass the frequency string 'h' to .resample() and apply an aggregation function such as .mean() or .agg(). Note that in pandas 2.2 and newer, legacy frequency aliases like 'H', 'M', and 'T' are deprecated in favor of lowercase 'h', month-end 'ME', and 'min'.

# Downsample to hourly mean values
hourly_means = df_sensor.resample("h").mean()

# Calculate multiple summary statistics simultaneously across channels
hourly_summary = df_sensor.resample("h").agg({
    "temperature_c": ["mean", "min", "max", "std"],
    "humidity_pct": ["mean", "std"]
})

print(hourly_summary.head(3))

Step 3: Control bin edges and labeling with closed, label, and origin

By default, sub-daily frequencies like 'h' or '15min' align intervals to midnight (origin='start_day') with the interval closed on the left (closed='left') and labeled using the left edge (label='left'). In an interval [10:00, 11:00), a measurement at exactly 10:00 is included, while a measurement at 11:00 falls into the next bin.

To include the right boundary in the interval and label each bin with its ending timestamp, configure closed='right' and label='right':

# Resample into 2-hour buckets closed and labeled on the right
hourly_right = df_sensor.resample("2h", closed="right", label="right").mean()

# Align intervals to the earliest timestamp in the data rather than midnight
hourly_start_aligned = df_sensor.resample("2h", origin="start").mean()

Step 4: Upsample low-frequency records and interpolate missing intervals

When aligning lower-frequency measurements to higher-frequency recording intervals (upsampling), pandas creates new timestamp buckets containing missing values (NaN). To impute these values, chain filling or interpolation methods:

# Sample daily aggregated metrics
daily_df = df_sensor.resample("D").mean()

# Upsample from daily to 6-hour intervals with forward-fill
upsampled_ffill = daily_df.resample("6h").ffill()

# Upsample from daily to 6-hour intervals using linear interpolation
upsampled_interp = daily_df.resample("6h").interpolate(method="linear")

print(upsampled_interp.head(4))

For mathematical background on piecewise polynomial and spline fitting in scientific programming, consult the guide on MATLAB interpolation.

Step 5: Resample without altering the primary DataFrame index

If your DataFrame uses a non-temporal index (such as participant IDs or specimen barcodes), you can pass the timestamp column name to the on parameter without calling set_index():

# Reset index to illustrate non-indexed timestamp columns
df_flat = df_sensor.reset_index().rename(columns={"index": "recorded_at"})

# Resample directly using the 'on' argument
resampled_col = df_flat.resample("3h", on="recorded_at").mean()
print(resampled_col.head(2))

Output and how to read it

Executing df.resample(rule) does not immediately compute values. Instead, it returns a Resampler object (specifically an instance of pandas.core.resample.DatetimeIndexResampler). This object acts as a deferred groupby mechanism waiting for an aggregation or transformation method.

When an aggregation method like .mean(), .sum(), or .agg() is evaluated, the resulting object exhibits the following characteristics:

  • Resulting Index: The output index is a DatetimeIndex whose frequency attribute (freq) reflects the target rule string (such as <Hour> or <Day>).
  • Bucket Timestamps: Each index value corresponds to the interval bin label determined by the label and origin settings. When label='left' is active, timestamp 2026-05-01 01:00:00 represents the interval spanning from 01:00:00 up to (but not including) 02:00:00.
  • Empty Bins: If no raw observations fall within a specific temporal window, aggregation methods return NaN for continuous measures and 0 for count methods like .count().
  • Multi-Level Columns: When applying dictionaries or lists of aggregation functions via .agg(), pandas returns a DataFrame with a two-level hierarchical column index containing the original field names at level 0 and the applied metric names at level 1.

Troubleshooting

Researchers commonly encounter several predictable exceptions and data anomalies when resampling time series in pandas. The table below lists these issues, their underlying causes, and direct solutions:

Observed Issue or Exception Root Cause Corrective Action
TypeError: Only valid with DatetimeIndex, TimedeltaIndex or PeriodIndex The DataFrame index consists of integers, strings, or floats, and the on parameter was not specified. Convert the date column using df['timestamp'] = pd.to_datetime(df['timestamp']) and either set it as the index with df.set_index('timestamp') or pass on='timestamp' to .resample().
FutureWarning: 'H' is deprecated and will be removed in a future version Use of legacy pandas 1.x uppercase frequency aliases ('H', 'M', 'T', 'S'). Update frequency strings to modern pandas 2.2+ standards: use 'h' for hours, 'min' for minutes, 's' for seconds, and 'ME' for month-end.
Unexpected bin alignment (e.g., intervals offset by minutes or hours) Default origin='start_day' anchors bins to midnight (00:00:00), which can fragment irregular logging windows. Explicitly set origin='start' to anchor intervals to the first timestamp, or provide an explicit timestamp string like origin='2026-05-01 08:00:00'.
Upsampled DataFrame contains entirely NaN values Calling an aggregation function like .mean() on an upsampled series with non-overlapping new bins. Use filling or interpolation methods such as .ffill(), .bfill(), or .interpolate(method='linear') rather than simple reductions.

Free alternatives (table)

While pandas is standard in Python scientific computing, alternative open-source software libraries provide time series resampling capabilities across different languages and computing architectures:

Tool / Package Language / Ecosystem Core Resampling Function Key Strengths in Research Primary Use Case
Polars Python / Rust group_by_dynamic(), upsample() Parallelized Rust core, memory-efficient streaming, zero-copy operations on large datasets. High-throughput laboratory sensor arrays exceeding system memory; see Polars vs pandas.
R (xts / zoo) R / CRAN period.apply(), to.period(), aggregate.zoo() Extensive econometric and biostatistical test suites; seamless integration with base R time series. Clinical trials and biometric research centered in the R statistical environment.
DuckDB SQL / In-process OLAP time_bucket(), date_trunc() Direct query execution over large Parquet and CSV files without memory overhead. Pre-aggregating multi-gigabyte observational logs before downstream analysis.
TimeSeries.jl Julia collapse() High mathematical performance and native support for continuous scientific computing models. Physics, geophysical simulations, and dynamic systems modeling.

FAQ

What is the difference between pandas resample and groupby?

Both methods perform split-apply-combine operations. However, groupby() requires exact matching of discrete values (such as categories or distinct dates), whereas resample() groups continuous temporal data into predefined time intervals (bins) based on calendar or clock frequencies, handling edge boundaries and missing intervals automatically.

How do you fix the FutureWarning for ‘H’ and ‘M’ in pandas resample?

In pandas 2.2 and later, uppercase aliases for hours ('H') and months ('M') are deprecated. Replace 'H' with lowercase 'h' for hourly frequency, 'M' with 'ME' for month-end frequency, and 'T' with 'min' for minute frequency.

Does pandas resample modify the DataFrame in place?

No. resample() never modifies the original DataFrame or Series in place. It produces a deferred Resampler object, and applying an aggregation or filling method yields a newly constructed DataFrame.

How do closed and label differ in pandas resample?

The closed parameter dictates which boundary of the time bin includes the boundary timestamp (e.g., closed='left' means [start, end)). The label parameter dictates which boundary timestamp is assigned to the output index row (e.g., label='left' uses the starting timestamp of the bin).

Sources (official docs)

Follow CASRAI

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

Ask CASRAI · free to try

Ask about pandas resample: Time Series Downsampling Guide

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 →