Индекс цен в pandas: как отделить подорожание от изменения корзины

Средняя цена проданной единицы упала, и отчёт сообщает, что товары подешевели. При этом закупщик видит повышение цен по каждой позиции. Обе цифры могут быть вычислены правильно: покупатели просто переключились на более дешёвый ассортимент. Чтобы ответить на вопрос о подорожании, зафиксируем состав корзины и пересчитаем её стоимость по новым ценам.

Какой вопрос задаём данным

Пусть в базовом месяце купили 10 единиц дешёвого товара и 90 единиц дорогого. В следующем месяце количества поменялись местами. Цена каждого товара выросла на 10%. Средняя фактическая цена единицы заметно упадёт из-за состава продаж. Она описывает покупку, но не отвечает на вопрос, во сколько обошёлся бы прежний набор товаров.

Для второго вопроса берём количества базового месяца и умножаем их сначала на старые цены, затем на новые. Отношение стоимости новой оценки к старой — индекс цен постоянной базовой корзины, часто называемый индексом Ласпейреса. Значение 1,10 означает, что именно этот набор стал дороже на 10%. Смысл индекса задают его веса — количества базового периода.

Подготовка важнее деления

В каждой строке должен быть один сопоставимый товар с ценами и количеством за оба месяца. Смена упаковки, объёма или состава нарушает сопоставимость. Цена бутылки литр и бутылки 0,9 литра должна быть приведена к одинаковой единице. Замена артикула требует согласованной таблицы соответствий, а не совпадения похожих названий.

В примере цены фиксированы внутри месяца. Если в данных несколько покупок по разным ценам, сначала решите, какую цену сравниваете: фактическую среднюю после скидок или цену из прайса на дату. Средняя после скидок отражает и изменение промо. Не смешивайте в одном столбце прайс одних товаров и фактическую цену других.

Полный расчёт на двух товарах

Таблица содержит цены и количества обоих месяцев. Код отдельно вычисляет средние фактические цены, стоимость неизменной корзины и проверяет полноту входов. Все денежные величины заданы в условных рублях; индекс безразмерен. Проверки полноты защищают от молчаливого исключения товара, у которого в новом месяце нет цены.

import pandas as pd
data = pd.DataFrame([
    ('basic',100,10,110,90), ('premium',1000,90,1100,10)
],columns=['sku','price0','qty0','price1','qty1'])
assert not data.sku.duplicated().any()
assert data[['price0','price1','qty0','qty1']].notna().all().all()
assert (data[['price0','price1']] > 0).all().all()
assert (data[['qty0','qty1']] >= 0).all().all()
old_cost = (data.price0*data.qty0).sum()
new_cost_same_basket = (data.price1*data.qty0).sum()
assert old_cost > 0 and data.qty0.sum()>0 and data.qty1.sum()>0
index = new_cost_same_basket/old_cost
avg0 = old_cost/data.qty0.sum()
avg1 = (data.price1*data.qty1).sum()/data.qty1.sum()
actual_ratio = avg1/avg0
print({'old_basket':int(old_cost),'new_same_basket':int(new_cost_same_basket),
       'price_index':round(float(index),4),'avg0':float(avg0),'avg1':float(avg1),
       'average_ratio':round(float(actual_ratio),4)})
assert old_cost == 91000 and new_cost_same_basket == 100100
assert abs(index-1.1) < 1e-12
assert avg0 == 910 and avg1 == 209

Два результата, два смысла

Стоимость базовой корзины выросла с 91000 до 100100 рублей: индекс равен 1,10. Фактическая средняя цена единицы упала с 910 до 209 рублей, потому что в новом месяце покупают преимущественно дешёвый товар. Для бюджета закупки прежнего набора нужен первый показатель. Для описания структуры фактических покупок полезен второй.

Нельзя просто усреднить проценты изменения цен товаров без весов. Такой расчёт даст одинаковое влияние редкой позиции и основного товара. В данном примере цены выросли одинаково, поэтому среднее случайно совпадёт с индексом. При разных изменениях совпадение исчезнет. В рабочей таблице полезно показывать вклад каждой позиции через её базовую стоимость.

Что делать с новыми и исчезнувшими товарами

Если товар снят с продажи, нулевая цена не является корректной заменой отсутствующей. Сначала найдите сопоставимую замену или посчитайте индекс по общей части ассортимента. Во втором случае покажите, какую долю базовой стоимости покрывают оставшиеся товары. Индекс по небольшой общей части нельзя выдавать за изменение стоимости всей исходной корзины.

Новые товары без базового количества не влияют на фиксированную корзину. Это нормально для выбранного вопроса, но со временем корзина устаревает. Запланируйте её обновление и храните старую версию, чтобы объяснять разрыв ряда. Если нужны долгие временные ряды, можно связывать короткие сопоставимые интервалы; правила обновления весов должны быть частью определения метрики.

Как использовать показатель в отчёте

Покажите индекс цен рядом с фактическими количеством, выручкой и средней ценой. В выводе напишите: прежняя корзина подорожала на 10%, а средняя покупаемая единица стала дешевле из-за переключения ассортимента. Такой текст снимает кажущееся противоречие и помогает выбрать действие: обсуждать закупочные цены или разбираться с изменением спроса покупателей.

Выбираем веса для конкретного решения

Базовая корзина удобна, когда нужно оценить прежний бюджет при новых ценах. Если вопрос относится к тому, как изменились расходы на текущий набор, фиксировать следует количества нового периода и оценивать их в обеих системах цен. Получится другой индекс: его смысл связан с текущими покупками. Разные веса отвечают на разные вопросы, поэтому выбирать результат по более удобной цифре нельзя.

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

Продолжить практику

Продолжить такой анализ можно в платной «Практической аналитике данных»: на кейсе продаж вы учитесь выбирать показатель, сравнивать периоды, проверять данные и объяснять результат. Затем расчёты переносятся на новый месяц и оформляются в DataLens и аналитическую записку. Откройте программу курса.

Продолжить на практике

  • Практическая аналитика данных ↗

    Превратите знания SQL или Python в аналитическую работу: проверяйте данные, считайте бизнес-метрики, стройте дашборды и объясняйте выводы на трёх прикладных кейсах.