Условие
Витрина обращений request_agg:
dt— дата.type_appeal— клиентский / партнёрский.direction— голос / чаты / заявки партнёра / исход / поддержка ритейлеров.theme,subtheme— тема и подтема.assembly_type,type_store_delivery— тип сборки и доставки.total_bid— кол-во обращений.numerator_csi— числитель для CSI (сумма «положительных» оценок).total_rates— знаменатель CSI (всего оценок).
Посчитать CSI по дням и каналам (direction) только для клиентских обращений. Считать только дни с достаточным числом оценок (фильтр шума).
Решение
Что такое CSI
CSI = numerator_csi / total_rates. В витрине уже агрегировано — нужно правильно сложить числитель и знаменатель отдельно, а не усреднить готовый CSI (это ошибка ratio-метрик).
Реализация
WITH agg AS (
SELECT
dt,
direction,
SUM(numerator_csi)::numeric AS num_sum,
SUM(total_rates)::numeric AS den_sum,
SUM(total_bid) AS bids_sum
FROM request_agg
WHERE type_appeal = 'Клиентский'
GROUP BY dt, direction
)
SELECT
dt,
direction,
bids_sum,
den_sum AS rates_sum,
CASE WHEN den_sum >= 30
THEN ROUND(num_sum / den_sum, 3)
ELSE NULL -- мало оценок - неустойчивая метрика
END AS csi
FROM agg
ORDER BY dt, direction;Почему «усреднять CSI» неправильно
Если CSI в день А считался по 1000 оценок (=0.5), а в день В — по 10 оценок (=0.9), их арифметическое среднее 0.7 ничего не значит. Правильно — сложить числитель (500+9=509) и знаменатель (1010), получить 0.504.
Это общее правило для всех ratio-метрик: CTR, CR, ROAS, NPS — никогда не усредняем готовое отношение.
Альтернатива — взвешенное среднее
SELECT direction,
SUM(numerator_csi) / NULLIF(SUM(total_rates), 0) AS csi_overall
FROM request_agg
WHERE type_appeal='Клиентский'
GROUP BY direction;Подводные камни
numerator_csiможет быть отрицательным в данных (если шкала включает -1 или штрафные оценки). В этой витрине так и есть: видны строки сnumerator_csi = -2. Учитывать, что CSI ∈ [-1; 1].total_rates < total_bid— норма: не все обращения получают оценку. Считаем CSI только поtotal_rates.- «Достаточное число оценок». Без порога CSI 1.0 при 1 оценке — мусор. Минимум 30 — эмпирический; в проде — биномиальный CI с lower bound (Wilson score) для рейтинга.
- Партнёрские обращения. В
request_aggесть оба типа; фильтрtype_appeal = 'Клиентский'обязателен. assembly_type/type_store_deliveryбывают NULL — не дублируем строки, но и не выкидываем.- Деление на 0.
NULLIF(den_sum, 0)— must.
Эталонный ответ
SUM(numerator_csi) / NULLIF(SUM(total_rates), 0) по (dt, direction) для клиентских обращений, с порогом по SUM(total_rates) ≥ 30. Никогда не усреднять готовое отношение по строкам — это типовая ошибка ratio-метрик.