Аномалии продаж в pandas: сравниваем понедельник с понедельником
В понедельник продажи упали на треть относительно воскресенья. Для магазина это может быть обычным недельным ритмом. Простой мониторинг должен сравнивать сопоставимые дни и сохранять понятное объяснение сигнала. Построим в pandas историческую базу по дню недели и проверим новый день по устойчивой к отдельным выбросам границе.
Какую величину контролируем
Возьмём число оплаченных заказов за полностью закрытый календарный день. Вход должен содержать все дни, включая нулевые, если они действительно закрыты. Отсутствующий кассовый файл не является нулевым спросом. Перед поиском аномалий нужна проверка завершённости поставки; иначе мониторинг будет регулярно сообщать о поломке выгрузки как о падении бизнеса.
Историческая база состоит из восьми завершённых недель. Для каждого дня недели считаем медиану заказов. Новый понедельник сравниваем с историческими понедельниками, вторник — со вторниками. Это убирает простейшую недельную сезонность. Медиана уменьшает влияние одного необычного дня, но не отменяет необходимость отдельно учитывать праздники, акции и длительные закрытия магазина.
Для разброса используем MAD: медиану абсолютных отклонений от медианы группы. Если обычные понедельники близки друг к другу, MAD небольшой. В отличие от стандартного отклонения, одна очень большая продажа слабее раздвигает границы. Здесь MAD используется напрямую, без преобразования в оценку стандартного отклонения.
Порог должен соответствовать действию
Сигнал срабатывает, когда абсолютное отклонение больше максимума из шести MAD и двадцати заказов. Число шесть и абсолютный минимум двадцать — демонстрационная политика, а не универсальная статистическая граница. Она означает: разбираем только отклонение, достаточно большое относительно истории и по операционному масштабу.
Абсолютный минимум нужен, в частности, когда MAD равен нулю. В стабильной группе все значения могут совпасть, и любое изменение на один заказ иначе стало бы сигналом. Для большого магазина минимум должен быть другим. Порог выбирают по стоимости пропущенного падения и времени команды на расследование ложных сигналов.
Исторические значения в примере построены так, чтобы расчёт можно было проверить. Для понедельника они меняются от 97 до 103, медиана равна 100, MAD — 1,5. Новый день с 70 заказами отклоняется на 30, что больше выбранной границы 20. Этот сигнал уже не объясняется обычной разницей понедельника и воскресенья.
import pandas as pd
import numpy as np
dates = pd.date_range("2026-08-03",periods=56,freq="D")
weekday_base = np.array([100,110,120,130,140,180,160])
week_offsets = np.array([-3,-2,-1,0,0,1,2,3])
h = pd.DataFrame({"date":dates})
h["weekday"] = h.date.dt.dayofweek
h["orders"] = weekday_base[h.weekday.to_numpy()] + np.repeat(week_offsets,7)
g = h.groupby("weekday").orders
base = g.agg(n="size",median="median")
base["mad"] = g.agg(lambda x:(x-x.median()).abs().median())
assert base.n.ge(8).all()
new_date = pd.Timestamp("2026-09-28")
observed = 70
b = base.loc[new_date.dayofweek]
threshold = max(6*b["mad"],20)
deviation = observed-b["median"]
alert = abs(deviation)>threshold
print({"baseline":b["median"],"MAD":b["mad"],"observed":observed,"deviation":deviation,"threshold":threshold,"alert":bool(alert)})
assert b["median"] == 100 and b["mad"] == 1.5
assert alertЧто делать после сигнала
Начните с проверки данных: закрыт ли день, все ли магазины прислали заказы, не изменился ли статус оплаты. Затем разложите падение по магазинам, каналам или категориям. Если почти всё отклонение пришлось на один магазин, можно проверить его работу и доступность товара. Если одновременно упали все каналы, вероятнее общая причина: техническая ошибка или ограничение продаж.
Для сигнала сохраняйте дату, наблюдаемое значение, базу, отклонение и правило порога. Одной красной точки недостаточно для расследования. Полезно прикладывать исходные восемь понедельников: сотрудник сразу увидит, соответствует ли история текущим условиям.
Как оценить полезность мониторинга
Прогоните правило по прошлым датам, каждый раз используя только предшествующую историю. Нельзя включать проверяемый день в собственную базу: он сдвинет медиану и разброс. Просмотрите сработавшие сигналы вместе с операционной командой и отметьте известные события. Такая ретроспектива покажет, сколько расследований требует выбранный порог.
После смены цен, рекламы или режима магазина база может устареть. Обновляйте окно и отдельно отмечайте структурные изменения. Сезонный мониторинг по восьми неделям не предназначен для годового цикла: декабрьские продажи лучше сравнивать с подходящим сезонным контекстом. Метод полезен как прозрачный первый уровень контроля, который команда способна объяснить и поддерживать.
Один из возможных источников ложного падения разобран отдельно: Продажи упали после обновления CRM: как проверить смену статусов в данных.
Как не превратить сигнал в ежедневный шум
В уведомлении полезно показывать направление изменения. Падение на тридцать заказов требует одной проверки, рост на тридцать — другой: возможно, сработала акция или появились дубли платежей. Одна и та же абсолютная граница ловит оба события, но маршрут расследования зависит от знака.
Если отклонение продолжается несколько дней, группируйте его в один открытый случай с обновляемым статусом. После подтверждения причины сохраняйте пометку в журнале: сбой выгрузки, закрытие магазина, акция или необъяснённое изменение. Эти записи помогают оценить полезность правила и позднее настроить порог. Без обратной связи мониторинг производит сигналы, но команда не узнаёт, какие из них действительно помогли обнаружить проблему.
Продолжить практику
В «Практической аналитике данных» вы разбираете распределения, динамику и сопоставимость периодов, затем формулируете вывод по данным. Кейсы продаж, клиентов и рекламы доступны через pandas или SQL. В финале вы повторяете анализ на данных нового месяца, собираете дашборд и готовите рекомендацию. Откройте программу курса.
Продолжить на практике
- Практическая аналитика данных ↗
Превратите знания SQL или Python в аналитическую работу: проверяйте данные, считайте бизнес-метрики, стройте дашборды и объясняйте выводы на трёх прикладных кейсах.
