Нашли ошибку?
продвинутыйpandas 3.0.6

Ресемплинг: resample и asfreq

Перейти к другой частоте временного ряда — из часов в дни, из дней в месяцы — или наоборот.

Нужно знать:date_range и временной индексГруппировка: groupby

Содержание статьи

Коротко

  • resample("D") — это groupby по интервалам времени: дальше нужна агрегация — .sum(), .mean(), .agg([...]).
  • Частоты те же, что в date_range: h, D, W, ME (метка — конец месяца), MS (начало месяца), QE, YE.
  • Понижение частоты (часы → дни) — агрегация; повышение (дни → часы) — заполнение: .ffill(), .interpolate().
  • asfreq("12h") просто берёт значения в нужные моменты, без агрегации.
  • Нужны даты в индексе; если даты в столбце — resample(..., on="столбец").

Синтаксис

s.resample(rule, on=None, label=None, closed=None).sum()
s.resample("D").agg(["sum", "max"])
s.resample("h").ffill(), s.resample("h").interpolate()
s.asfreq("12h")

Параметры

ПараметрЧто делаетПо умолчанию
ruleновая частота: "h", "D", "W", "ME", "MS", "QE", "YE"…обязательный
onстолбец с датами вместо индексаNone
labelкакой границей подписать интервал: "left" или "right"зависит от частоты
closedкакая граница интервала входит в него: "left" или "right"зависит от частоты

Примеры

Данные для примеровиспользуются во всех примерах ниже
hours = pd.date_range("2024-03-01 08:00", periods=10, freq="6h")
orders = pd.Series([5, 12, 9, 3, 7, 15, 8, 2, 6, 11], index=hours, name="orders")
Из часов в дни
orders.resample("D").sum()                      # по дням
Вывод
2024-03-01    26
2024-03-02    33
2024-03-03    19
Freq: D, Name: orders, dtype: int64
Несколько итогов
orders.resample("D").agg(["sum", "max", "count"])
Вывод
            sum  max  count
2024-03-01   26   12      3
2024-03-02   33   15      4
2024-03-03   19   11      3
По месяцам: ME
days = pd.date_range("2024-01-25", periods=10, freq="D")
pd.Series(range(10), index=days).resample("ME").sum()   # по месяцам; метка — последний день
Вывод
2024-01-31    21
2024-02-29    24
Freq: ME, dtype: int64
По месяцам: MS
days = pd.date_range("2024-01-25", periods=10, freq="D")
pd.Series(range(10), index=days).resample("MS").sum()   # метка — первый день месяца
Вывод
2024-01-01    21
2024-02-01    24
Freq: MS, dtype: int64
Чаще данных: ffill
daily = pd.Series([100, 130, 90], index=pd.date_range("2024-03-01", periods=3, freq="D"))
daily.resample("12h").ffill()                   # чаще, чем данные: заполняем предыдущим
Вывод
2024-03-01 00:00:00    100
2024-03-01 12:00:00    100
2024-03-02 00:00:00    130
2024-03-02 12:00:00    130
2024-03-03 00:00:00     90
Freq: 12h, dtype: int64
Чаще данных: интерполяция
daily = pd.Series([100, 130, 90], index=pd.date_range("2024-03-01", periods=3, freq="D"))
daily.resample("12h").interpolate()             # или линейно между точками
Вывод
2024-03-01 00:00:00    100.0
2024-03-01 12:00:00    115.0
2024-03-02 00:00:00    130.0
2024-03-02 12:00:00    110.0
2024-03-03 00:00:00     90.0
Freq: 12h, dtype: float64
asfreq без агрегации
orders.asfreq("12h")                            # просто выбрать моменты, без агрегации
Вывод
2024-03-01 08:00:00    5
2024-03-01 20:00:00    9
2024-03-02 08:00:00    7
2024-03-02 20:00:00    8
2024-03-03 08:00:00    6
Freq: 12h, Name: orders, dtype: int64
Свои функции для столбцов
df = pd.DataFrame({"orders": orders, "revenue": orders * 350})
df.resample("D").agg({"orders": "sum", "revenue": "mean"})
Вывод
            orders      revenue
2024-03-01      26  3033.333333
2024-03-02      33  2887.500000
2024-03-03      19  2216.666667
Даты в столбце
events = orders.reset_index().rename(columns={"index": "time"})
events.resample("D", on="time")["orders"].sum()   # даты в столбце, а не в индексе
Вывод
time
2024-03-01    26
2024-03-02    33
2024-03-03    19
Freq: D, Name: orders, dtype: int64

Подводные камни

Индекс без дат

resample для обычного индексаошибка: TypeError
pd.Series([1, 2, 3]).resample("D").sum()
Ошибка
TypeError: Only valid with DatetimeIndex, TimedeltaIndex or PeriodIndex, but got an instance of 'RangeIndex'

Сделайте даты индексом (set_index("time")) или передайте on=.

resample('M') больше не работает

Конец месяца теперь обозначается ME, начало — MS. Подробности и пример ошибки — в статье date_range.