Нашли ошибку?
Скачать чистый
урок 2 из 4≈ 20 минупражнения: 0 из 4

Пересчёт частоты

resample превращает дневной ряд в недельный, месячный или квартальный: сумма, среднее и другие итоги по периодам. Обозначения частот, почему "M" больше не работает, неполные недели по краям и пустые периоды.

Python запустится при первом выполнении

Дневные данные слишком подробны: 365 чисел не окинуть взглядом, и в них много случайных колебаний. Обычно их укрупняют — смотрят выручку по неделям или месяцам. Это та же группировка, только группы — отрезки времени. Для неё есть отдельный метод, который знает календарь.

[ ]Два ряда на каждый день года: выручка sales и число заказов order_count
import pandas as pd

orders = pd.read_csv("data/shop_orders.csv", parse_dates=["date"])
orders["revenue"] = orders["price"] * orders["quantity"]
daily = orders.groupby("date")["revenue"].sum()
calendar = pd.date_range("2025-01-01", "2025-12-31")
sales = daily.reindex(calendar, fill_value=0)
order_count = orders.groupby("date")["order_id"].nunique().reindex(calendar, fill_value=0).rename("orders")
print(sales.head(3))
order_count.head(3)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
2025-01-01     9060
2025-01-02    10450
2025-01-03    18620
Freq: D, Name: revenue, dtype: int64
2025-01-01    3
2025-01-02    4
2025-01-03    5
Freq: D, Name: orders, dtype: int64

Примеры в уроке — на числе заказов, упражнения — на выручке. У ряда заказов имя orders (метод rename у Series меняет имя ряда): без него в выводе стояло бы Name: order_id — имя столбца, из которого ряд посчитан.

resample

Метод resample («пересчитать частоту») работает как groupby: сначала делит ряд на периоды, потом к каждому применяется итог. Период задают строкой-обозначением:

[ ]Заказов по месяцам
order_count.resample("ME").sum().head(4)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
2025-01-31    143
2025-02-28    138
2025-03-31    134
2025-04-30    133
Freq: ME, Name: orders, dtype: int64

Строка Freq: ME внизу — частота получившегося ряда.

"ME" значит «month end» — конец месяца: каждое значение подписано последним днём своего месяца. Если удобнее подписывать началом, есть "MS" («month start»):

[ ]Те же суммы, подпись — первый день месяца
order_count.resample("MS").sum().head(4)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
2025-01-01    143
2025-02-01    138
2025-03-01    134
2025-04-01    133
Freq: MS, Name: orders, dtype: int64

Суммы одинаковые — отличается только метка.

Частые обозначения:

Обозначение Период
"D" день
"W" неделя
"ME", "MS" месяц (метка — конец или начало)
"QE", "QS" квартал
"YE", "YS" год

В старых учебниках и ответах в интернете месяц обозначен одной буквой "M". В pandas 3 это ошибка:

[ ]Старое обозначение месяцаошибка: ValueError
order_count.resample("M").sum()
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
ValueError: Invalid frequency: M. Failed to parse with error message: ValueError("'M' is no longer supported for offsets. Please use 'ME' instead.")

Метка периода — обычная дата. У отдельной даты части достают без приставки .dt: .month — номер месяца, .quarter — номер квартала.

[ ]Метка второго квартала: дата его конца, номер месяца и квартала
quarter = order_count.resample("QE").sum().index[1]
print(quarter)
print(quarter.month, quarter.quarter)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
2025-06-30 00:00:00
6 2
[ ]Упражнение 1Лучший и худший месяц решено

Сохраните в monthly выручку по месяцам. В best_month сохраните номер месяца с наибольшей выручкой, в worst_month — с наименьшей.

monthly = ...
best_month = ...
worst_month = ...

Недели и их края

[ ]Заказов по неделям
weekly_orders = order_count.resample("W").sum()
print(len(weekly_orders))
weekly_orders.head(3)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
53
2025-01-05    18
2025-01-12    39
2025-01-19    40
Freq: W-SUN, Name: orders, dtype: int64

Недель получилось 53, и подписаны они воскресеньями: "W" считает неделю с понедельника по воскресенье и ставит метку на её конец. Об этом и говорит Freq: W-SUN — «недели, которые кончаются в воскресенье» (Sunday). Но год не обязан начинаться в понедельник. Сколько дней попало в первую, вторую и последнюю неделю, покажет count:

[ ]Дней в неделях
print(order_count.resample("W").count().iloc[[0, 1, -1]])
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
2025-01-05    5
2025-01-12    7
2026-01-04    3
Name: orders, dtype: int64

1 января 2025 года — среда, поэтому в первой неделе пять дней. Последняя неделя заканчивается уже в 2026 году, и от неё в наших данных три дня.

Вопрос
two_weeks = pd.Series(1, index=pd.date_range("2025-03-03", "2025-03-16"))
print(two_weeks.resample("W").sum().tolist())

3 марта 2025 года — понедельник, 16 марта — воскресенье. Что выведет этот код?

[ ]Упражнение 2Лучшая неделя решено

Сохраните в weekly выручку по неделям. В full_weeks — только полные недели: без первой и последней. В best_week_end сохраните дату окончания недели с наибольшей выручкой, в week_mean — среднюю выручку полной недели.

weekly = ...
full_weeks = ...
best_week_end = ...
week_mean = ...

Не только сумма и не только Series

После resample доступны те же итоги, что после groupby: sum, mean, max, min, count, agg. А если пересчитывать таблицу, столбец выбирают так же — в скобках:

[ ]Средний дневной максимум по месяцам
weather = pd.read_csv("data/weather.csv", parse_dates=["date"])
moscow = weather[weather["city"] == "Москва"].set_index("date")
moscow.resample("ME")["temp_max"].mean().round(1).head(3)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
date
2025-01-31   -3.8
2025-02-28   -4.7
2025-03-31    1.6
Freq: ME, Name: temp_max, dtype: float64

Выбор итога зависит от смысла: выручку и осадки складывают, температуру усредняют.

[ ]Упражнение 3Температура и осадки по месяцам решено

Сохраните в climate таблицу по месяцам для Москвы: temp — средний temp_max, rain — сумма precip_mm; округление до одного знака. В rainiest сохраните номер самого дождливого месяца.

climate = ...
rainiest = ...

Кварталы и пустые периоды

[ ]Заказов по кварталам
order_count.resample("QE").sum()
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
2025-03-31    415
2025-06-30    401
2025-09-30    302
2025-12-31    458
Freq: QE-DEC, Name: orders, dtype: int64

Freq: QE-DEC — кварталы года, который кончается в декабре (December), то есть обычного календарного.

У resample есть важное отличие от groupby: он создаёт все периоды от начала до конца ряда — даже те, в которые не попало ни одного значения. Возьмём исходный ряд daily, где дней без продаж просто нет:

[ ]2 июля: сумма — ноль, среднее — пропуск
print(daily.resample("D").sum().loc["2025-07-01":"2025-07-03"])
print(daily.resample("D").mean().loc["2025-07-01":"2025-07-03"])
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
date
2025-07-01    5370
2025-07-02       0
2025-07-03    3110
Freq: D, Name: revenue, dtype: int64
date
2025-07-01    5370.0
2025-07-02       NaN
2025-07-03    3110.0
Freq: D, Name: revenue, dtype: float64

resample("D") вернул в ряд пропавший день. Сумма пустого периода — ноль, а среднее — NaN: усреднять нечего. Так resample("D").sum() восстанавливает пропущенные дни внутри ряда — от первой его даты до последней. Дни до первой и после последней даты он не достроит; для этого нужен reindex с полным календарём.

[ ]Упражнение 4Доли кварталов решено

Сохраните в quarterly выручку по кварталам, в quarter_share — долю каждого квартала в выручке года (три знака). В weak_quarter сохраните номер самого слабого квартала.

quarterly = ...
quarter_share = ...
weak_quarter = ...

Итоги

  • ряд.resample("частота").sum() — итог по периодам; нужен индекс из дат.
  • "W" — неделя, "ME" / "MS" — месяц, "QE" — квартал; "M" в pandas 3 не работает.
  • Сумму — для того, что накапливается (выручка, осадки); среднее — для уровня (температура, цена).
  • Периоды по краям могут быть неполными — не сравнивайте их с полными.
  • Пустые периоды resample создаёт сам: сумма — ноль, среднее — NaN.

Подробнее в справочнике

Нашли ошибку?