# Аналитика курьеров по прошедшим дням

Пользователю предоставляется следующая информация:

1. Временной интервал, за который представлены данные;
2. Прогнозное количество заказов для указанного интервала (ожидаемое значение, сформированное [прогнозной моделью](https://bookstack.ally.software/books/texniceskaia-dokumentaciia/page/opisanie-prognoznoi-modeli) на основе данных, описанных в [статье](https://bookstack.ally.software/books/texniceskaia-dokumentaciia/page/rabota-s-dannymi-dlia-prognozov));
3. Фактическое количество заказов за интервал (реальное значение, извлеченное из [базы данных ВкусВилл](https://bookstack.ally.software/books/texniceskaia-dokumentaciia/page/rabota-s-dannymi-dlia-prognozov));
4. Оценка точности прогноза, рассчитываемая как симметричная средняя абсолютная процентная ошибка. ```
    (2 * (факт - прогноз) / (факт + прогноз))
    ```

Возможные значения:

- "Попадание" (прогноз был в пределах нормы если разница между фактом и прогнозом меньше либо равна 3 или оценка точности &lt; 0,15),
- "Недопрогноз" (прогноз был занижен, фактическое значение выше если оценка точности &gt; 0),
- "Перепрогноз" (прогноз был завышен, фактическое значение ниже если оценка точности &lt; 0)

[![04iimage.png](https://bookstack.ally.software/uploads/images/gallery/2025-09/scaled-1680-/XRO04iimage.png)](https://bookstack.ally.software/uploads/images/gallery/2025-09/XRO04iimage.png)

---

Прогнозное значение извлекается из таблицы [time\_series](https://bookstack.ally.software/link/733#bkmrk-%D0%A5%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D1%80%D0%B5%D0%B7%D1%83%D0%BB%D1%8C%D1%82%D0%B0%D1%82%D0%BE%D0%B2), из записей с типом 6 (обозначающим прогноз по геозонам для доставки заказов). Значение берется из поля value.

[![hLIimage.png](https://bookstack.ally.software/uploads/images/gallery/2025-09/scaled-1680-/hliimage.png)](https://bookstack.ally.software/uploads/images/gallery/2025-09/hliimage.png)

---

Фактическое значение рассчитывается из представления time\_series\_deliv\_hourly, созданного на основе таблицы time\_series и содержащего данные о заказах курьеров. Количество заказов определяется суммированием значений поля cnt (количество доставленных заказов) всех записей за выбранный интервал. Пример: для интервала 00:00–01:00 2 августа сумма значений cnt (8 + 1 + 4 + 1 + 1 + 1 + 3 + 2 + 1 + 2 + 1 + 1 + 1 + 4 + 1 + 2 + 2 + 2 + 3 + 4 + 5 + 1 + 1 + 1 + 1 + 1) равна 55.

[![D0Kimage.png](https://bookstack.ally.software/uploads/images/gallery/2025-09/scaled-1680-/d0kimage.png)](https://bookstack.ally.software/uploads/images/gallery/2025-09/d0kimage.png)

---

Для отображения всех этих данных в интерфейсе используется настройка dayPlaceTransform, которая формирует массив $hours. Массив содержит объекты для каждого часа суток (0–23) с соответствующими полями:

- hour — текущий час;
- stat — прогнозное количество заказов на этот час;
- plan — фактическое количество заказов на этот час;
- delta — отклонение между прогнозом и фактическим значением.
- smape — относительная ошибка прогноза, чтобы оценить его качество независимо от масштаба данных (симметричная средняя абсолютная процентная ошибка).
- err — ошибка прогноза: 0 — в пределах нормы (попадание), 1 — недопрогноз (прогноз занижен), -1 — перепрогноз (прогноз завышен).

Код, формирующий массив представлен ниже.

```javascript
$hours := [0..23].(
    $statObj := $lookup($hourStat, $string($));
    $stat := $number($inPast ? $statObj.cnt : $statObj.cnt) * $extraNorm;
    $plan := $number([$lookup($eventsStat, $string($)).sum_qty, 0][0]);
    $delta := $stat
        ? $inPast
            ? $round($plan - $stat, 1)
            : $round(($stat - $plan) / $speed)
        : 0;
    $smape := 2 * ($plan - $stat) / ($plan + $stat);
    $err := ($abs($delta) <= 3 or $abs($smape) < 0.15)
        ? 0
        : $smape > 0
            ? 1
            : -1;
    {
        "hour": $,
        "stat": $round($stat,1),
        "plan": $round($plan,1),
        "delta": $delta,
        "smape": $smape,
        "err": $err
    };
)
```