Метрики и сравнение: первый самостоятельный анализ

Почему заказы растут, а выручка падает: заказы × средний чек

Содержание курса

Как собрать таблицу с итогами и не запутаться в округлении

Чтобы подготовить готовый отчет, объединяют помесячные строки и итоговую строку TOTAL, после чего форматируют вывод.

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

Вариант на SQL

SQL · SQLite
SELECT 1.0 * 16200 / 7 AS aov_full,
       ROUND(1.0 * 16200 / 7, 2) AS aov_display,
       7 * ROUND(1.0 * 16200 / 7, 2) AS revenue_from_display,
       7 * (1.0 * 16200 / 7) AS revenue_from_full;

Результат проверки:

aov_full aov_display revenue_from_display revenue_from_full
2314.285714285714 2314.29 16200.03 16200.0

Вариант на pandas

Python · pandas
aov_full = 16200 / 7
aov_display = round(aov_full, 2)
print(aov_full)
print(aov_display)
print(7 * aov_display)
print(7 * aov_full)

Вывод программы:

Результат
2314.285714285714
2314.29
16200.029999999999
16200.0

Произведение дает рубля. Разница в 3 копейки вызвана исключительно экранным округлением, а не потерей данных или ошибкой отбора строк. Поэтому в расчетной модели всегда сохраняют точные целые компоненты ( и ) и неокругленное отношение, а функцию ROUND() или метод .round(2) применяют только к финальному представлению.

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

В SQL через обобщенное табличное выражение (WITH) рассчитываются помесячные компоненты, к которым через UNION ALL прикрепляется строка TOTAL:

SQL · SQLite
WITH monthly AS (
  SELECT strftime('%Y-%m', order_date) AS month,
         COUNT(*) AS paid_orders,
         SUM(gross_revenue) AS gross_revenue
  FROM demo_orders
  WHERE status = 'paid'
    AND order_date >= '2024-03-01'
    AND order_date < '2024-05-01'
  GROUP BY strftime('%Y-%m', order_date)
), report AS (
  SELECT month, paid_orders, gross_revenue,
         1.0 * gross_revenue / paid_orders AS aov
  FROM monthly
  UNION ALL
  SELECT 'TOTAL', SUM(paid_orders), SUM(gross_revenue),
         1.0 * SUM(gross_revenue) / SUM(paid_orders)
  FROM monthly
)
SELECT month, paid_orders, gross_revenue, ROUND(aov, 2) AS aov
FROM report
ORDER BY month;

В pandas формируется отдельный однострочный DataFrame для строки TOTAL и объединяется с помесячной таблицей с помощью pd.concat:

Python · pandas
total_orders = int(monthly["paid_orders"].sum())
total_revenue = int(monthly["gross_revenue"].sum())
total = pd.DataFrame([{
    "month": "TOTAL",
    "paid_orders": total_orders,
    "gross_revenue": total_revenue,
    "aov": total_revenue / total_orders,
}])
report = pd.concat([monthly, total], ignore_index=True)
shown = report.copy()
shown["aov"] = shown["aov"].round(2)
print(shown.to_string(index=False))

Оба варианта дают одинаковую финальную структуру:

month paid_orders gross_revenue aov
2024-03 3 9000 3000.00
2024-04 4 7200 1800.00
TOTAL 7 16200 2314.29

При сохранении результата в CSV-файл (например, report.to_csv('monthly_paid_report.csv', index=False)) аргумент index=False обязателен, чтобы не добавлять в файл безымянную колонку со служебными индексами строк.

Начать заново?

Помощник начнёт новый диалог по этой задаче. Текущая переписка останется в истории до конца срока хранения.

О переписке

Можно приложить до трёх фото PNG, JPEG или WebP по 5 МБ.

Переписка и фото хранятся 90 дней после последнего принятого сообщения. Преподаватель получит доступ к диалогу, когда вы попросите его помочь.

Проверка решения остаётся отдельным действием.