Условие
Даны помесячные продажи и товарный запас по 5 брендам за 2021–2023 (4 мес.) гг.
- Сводная таблица «бренд × месяц × год».
- Коэффициенты сезонности (по 2021 + 2022).
- Прогноз продаж на май–декабрь 2023 для каждого бренда с учётом сезонности.
- Оборачиваемость товарного запаса в месяцах.
Решение
Коэффициенты сезонности
Sезон-коэффициент месяца m = mean(sales_m_2021, sales_m_2022) / mean(sales_year).
import pandas as pd, numpy as np
df = pd.read_excel('Sales.xlsx', sheet_name='Sales')
df['Год'] = df.Год.astype(int)
df['Месяц_Num'] = pd.to_datetime(df.Месяц, format='%B').dt.month
base = df[df.Год.isin([2021, 2022])]
month_avg = base.groupby(['Бренд','Месяц_Num']).Продажи.mean()
year_avg = base.groupby('Бренд').Продажи.mean()
seas = (month_avg / year_avg).rename('seas').reset_index()
print(seas.pivot(index='Бренд', columns='Месяц_Num', values='seas'))Прогноз май–декабрь 2023
Идея: средний месяц 2023 (по январю-апрелю с поправкой на сезонность) умножаем на сезон-коэф каждого месяца.
known_2023 = df[(df.Год==2023)]
# «Расшумленный» базовый уровень: divide by seas
base_2023 = known_2023.merge(seas, on=['Бренд','Месяц_Num'])
base_2023['adj'] = base_2023.Продажи / base_2023.seas
base_per_brand = base_2023.groupby('Бренд').adj.mean() # стационарный уровень
forecast_months = list(range(5, 13))
forecast_rows = []
for brand, lvl in base_per_brand.items():
for m in forecast_months:
s = seas[(seas.Бренд==brand)&(seas.Месяц_Num==m)].seas.iloc[0]
forecast_rows.append({'Бренд':brand, 'Месяц':m, 'Прогноз': lvl * s})
fc = pd.DataFrame(forecast_rows)Оборачиваемость
Оборачиваемость в месяцах = средний запас / продажи в месяц.
df['Оборач'] = df['Товарныйзапаснаконецпериода'] / df.Продажи
piv = df.pivot(index=['Бренд','Год'], columns='Месяц_Num', values='Оборач')Подводные камни
- Коэф сезонности на 2 годах нестабилен — особенно для брендов 4 и 5, появившихся в 2022. Для них сезонность считать нечего.
- У Бренда 4 в 2023 продажи резко падают (
Янв 61послеДек 360) — возможно, бренд снимается с продаж. Прогноз будет дико переоценён. - Декабрь — пиковый месяц (праздники), коэф ~3–4. Не путать сезон с трендом.
- Оборачиваемость по запасу на конец периода может быть отрицательной, если продали больше, чем привезли.
NULLIFобязательно. - Лучшая практика — Holt-Winters или SARIMA вместо «среднего × сезон».
Эталонный ответ
Коэф. сезонности по 2021–2022 → базовый уровень 2023 = avg(known/seas) → прогноз = base × seas. Оборачиваемость = stock / sales.