Время цикла закупки: медиана и хвост
«Средний срок закупки — 30 дней» — фраза, которая ничего не описывает, если половина заказов закрывается за 20 дней, а каждый десятый тянется три месяца. Среднее складывает быстрые и медленные заказы и показывает число, которого не было ни у одного заказа.
Поэтому время цикла смотрят распределением: медианой (типичный случай) и перцентилями (хвост). Медиана устойчива к выбросам, p90 показывает, сколько ждёт каждый десятый заказ, p99 — крайние случаи, из-за которых срываются сроки.
Что именно измеряем
Заголовок раздела «Что именно измеряем»В датасете две даты: bids.bid_date — дата предложения поставщика
и purchases.order_date — дата заказа. Разница между самой ранней датой
предложения и датой заказа — это время от появления первого предложения
до принятия решения.
Это не весь цикл закупки. За ним остаются заявка, согласование и сбор предложений, а перед поставкой — ещё и срок производства. В данных этих дат нет, поэтому измеряем отрезок, который есть, и называем его точно: цикл от первого предложения до заказа. Подменять им «время цикла закупки» в отчёте нельзя — цифры будут несопоставимы с теми, где считают от заявки.
purchases и bids, соединённые по order_id. Цикл считается на заказ,
поэтому предложения сначала сворачиваются: min(bid_date) на заказ.
Десять заказов без предложений в расчёт не попадают — у них нет начальной
точки. Их судьба разобрана ниже.
Запрос: распределение
Заголовок раздела «Запрос: распределение»WITH c AS ( SELECT p.id, p.order_date - min(b.bid_date) AS days FROM purchases p JOIN bids b ON b.order_id = p.id GROUP BY p.id, p.order_date)SELECT count(*) AS "заказов", round(avg(days), 1) AS "среднее, дней", round(percentile_cont(0.5) WITHIN GROUP (ORDER BY days), 1) AS "медиана", round(percentile_cont(0.9) WITHIN GROUP (ORDER BY days), 1) AS "p90", round(percentile_cont(0.99) WITHIN GROUP (ORDER BY days), 1) AS "p99", max(days) AS "максимум"FROM c;┌─────────┬───────────────┬─────────┬──────┬───────┬──────────┐│ заказов │ среднее, дней │ медиана │ p90 │ p99 │ максимум │├─────────┼───────────────┼─────────┼──────┼───────┼──────────┤│ 390 │ 30.3 │ 20.5 │ 57.0 │ 208.2 │ 239 │└─────────┴───────────────┴─────────┴──────┴───────┴──────────┘Разбор распределения
Заголовок раздела «Разбор распределения»Медиана 20,5 дня, среднее 30,3 — на 48% больше. Разрыв означает, что быстрых заказов много, но их перевес не компенсирует длинный хвост: он и тянет среднее вверх.
p90 равен 57 дням: каждый десятый заказ идёт почти в три раза дольше типичного. p99 — 208 дней, максимум — 239. Это не единичная ошибка ввода: заказы длиннее 150 дней есть в семи категориях из девяти, и именно они определяют, попадёт ли поставка в срок.
Для управления этого достаточно. Медиана — то, что можно обещать в регламенте. p90 — то, что нужно объяснять. p99 — то, что нужно разбирать по одному заказу.
Запрос: по категориям
Заголовок раздела «Запрос: по категориям»WITH c AS ( SELECT p.id, p.category, p.order_date - min(b.bid_date) AS days FROM purchases p JOIN bids b ON b.order_id = p.id GROUP BY p.id, p.category, p.order_date)SELECT category AS "категория", count(*) AS "заказов", round(percentile_cont(0.5) WITHIN GROUP (ORDER BY days), 0) AS "медиана", round(percentile_cont(0.9) WITHIN GROUP (ORDER BY days), 0) AS "p90", max(days) AS "максимум"FROM c GROUP BY 1 ORDER BY 3 DESC;┌─────────────────┬─────────┬─────────┬───────┬──────────┐│ категория │ заказов │ медиана │ p90 │ максимум │├─────────────────┼─────────┼─────────┼───────┼──────────┤│ Упаковка │ 47 │ 30.0 │ 56.0 │ 207 ││ Спецодежда │ 39 │ 26.0 │ 62.0 │ 222 ││ Канцелярия │ 24 │ 26.0 │ 132.0 │ 239 ││ Крепёж │ 47 │ 24.0 │ 53.0 │ 233 ││ Химия и ГСМ │ 22 │ 22.0 │ 56.0 │ 163 ││ Электрика │ 47 │ 21.0 │ 55.0 │ 155 ││ Металлопрокат │ 71 │ 20.0 │ 51.0 │ 63 ││ Логистика │ 48 │ 18.0 │ 51.0 │ 62 ││ ИТ-оборудование │ 45 │ 14.0 │ 59.0 │ 157 │└─────────────────┴─────────┴─────────┴───────┴──────────┘Разбор по категориям
Заголовок раздела «Разбор по категориям»Медианы расходятся в два раза: 14 дней у ИТ-оборудования и 30 у Упаковки. Вероятное объяснение: там, где поставщик один и спецификация описана, решение принимают быстро; там, где рынок шире, дольше собирают предложения.
Но смотреть надо не только на медиану. У Канцелярии медиана 26 дней, а p90 — 132: каждый десятый заказ идёт в пять раз дольше типичного. У Металлопроката при медиане 20 дней максимум 63 — хвоста почти нет. Это два разных процесса, хотя медианы близки: в первом случае есть проблема, которую не видно по среднему, во втором процесс предсказуем.
Отсюда правило: категорию с высоким p90 при нормальной медиане надо разбирать отдельно. Там обычно прячутся согласования, которые запускаются не всегда, а по условию — например, при сумме выше порога.
Заказы без предложений
Заголовок раздела «Заказы без предложений»SELECT p.category AS "категория", count(*) AS "заказов без предложений"FROM purchases pWHERE NOT EXISTS (SELECT 1 FROM bids b WHERE b.order_id = p.id)GROUP BY 1 ORDER BY 2 DESC, 1;┌─────────────────┬─────────────────────────┐│ категория │ заказов без предложений │├─────────────────┼─────────────────────────┤│ ИТ-оборудование │ 3 ││ Химия и ГСМ │ 2 ││ Крепёж │ 1 ││ Металлопрокат │ 1 ││ Спецодежда │ 1 ││ Упаковка │ 1 ││ Электрика │ 1 │└─────────────────┴─────────────────────────┘Десять заказов прошли без предложений: у них нет ни одной строки в bids.
В расчёт времени цикла они не попали, и это правильно — считать их «быстрыми»
было бы ошибкой: у них не было этапа, а не быстрый этап.
В отчёте такие заказы показывают отдельной строкой. Если их доля растёт, это сигнал: конкуренция падает не потому, что поставщики не хотят участвовать, а потому что закупку провели в обход процедуры.
Типичные ошибки
Заголовок раздела «Типичные ошибки»| Ошибка | Что происходит | Как правильно |
|---|---|---|
| Показывать среднее время цикла | Среднее выше медианы на 48% и не описывает типичный заказ | Медиана как основной показатель, среднее — справочно |
| Считать цикл по одной дате предложения, а не по минимальной | Если взять, например, максимум, получится время до последнего предложения | Начало цикла — самое раннее предложение |
| Включать заказы без предложений с нулевым циклом | Медиана падает, картина улучшается на пустом месте | Исключать и показывать отдельно |
| Считать среднее по категориям, а потом усреднять категории | Мелкая категория весит столько же, сколько крупная | Считать по заказам или взвешивать по объёму |
| Сравнивать цикл «от предложения» с циклом «от заявки» | Разные отрезки, цифры несопоставимы | Фиксировать начало и конец отрезка в описании метрики |
Что читать дальше
Заголовок раздела «Что читать дальше»- Экономия против базовой цены — вторая метрика эффективности
- Время цикла закупки — методика: какие отрезки считать
- KPI закупок — как метрики складываются в отчёт