Как посчитать Gini coefficient в SQL

Закрепи формулу gini coefficient в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать gini coefficient в Telegram

Зачем Gini

Gini coefficient — мера неравенства. В макроэкономике — про доходы населения, в продукте — про любую неравномерность: выручка по клиентам, активность по пользователям, продажи по SKU. 0 = все равны, 1 = всё у одного.

В отличие от HHI, Gini чувствителен к распределению в средней части, не только к топу. Подходит для вопросов вида: «Сколько процентов пользователей делает 80% выручки?»

Через кривую Лоренца

Идея: упорядочиваем игроков по возрастанию, строим cumulative share по N и по выручке, считаем площадь между диагональю равенства и кривой Лоренца.

Формула через ranks:

Gini = (Σ (2*i − N − 1) * x_i) / (N * Σ x_i)

где x_i — значение i-го элемента в отсортированной выборке.

Gini в SQL

WITH ranked AS (
    SELECT
        customer_id,
        SUM(amount) AS revenue,
        ROW_NUMBER() OVER (ORDER BY SUM(amount)) AS rnk,
        COUNT(*) OVER () AS n
    FROM orders
    WHERE order_date >= '2026-01-01'
    GROUP BY customer_id
)
SELECT
    SUM((2 * rnk - n - 1) * revenue)::NUMERIC
    / NULLIF(n * SUM(revenue), 0) AS gini_coefficient
FROM ranked;

Результат в [0, 1]. На реальных продуктах обычно 0.5–0.9 — выручка крайне неравномерна.

Gini по сегментам

В каких странах самая большая неравномерность по выручке:

WITH ranked AS (
    SELECT
        u.country,
        o.customer_id,
        SUM(o.amount) AS revenue,
        ROW_NUMBER() OVER (PARTITION BY u.country ORDER BY SUM(o.amount)) AS rnk,
        COUNT(*) OVER (PARTITION BY u.country) AS n
    FROM orders o
    JOIN users u USING (customer_id)
    WHERE o.order_date >= CURRENT_DATE - INTERVAL '90 days'
    GROUP BY u.country, o.customer_id
)
SELECT
    country,
    MAX(n) AS customers,
    SUM((2 * rnk - n - 1) * revenue)::NUMERIC
    / NULLIF(MAX(n) * SUM(revenue), 0) AS gini
FROM ranked
GROUP BY country
HAVING MAX(n) >= 30
ORDER BY gini DESC;
Закрепи формулу gini coefficient в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать gini coefficient в Telegram

Gini во времени

Тренд неравенства помесячно:

WITH ranked AS (
    SELECT
        DATE_TRUNC('month', order_date)::DATE AS month,
        customer_id,
        SUM(amount) AS revenue,
        ROW_NUMBER() OVER (PARTITION BY DATE_TRUNC('month', order_date) ORDER BY SUM(amount)) AS rnk,
        COUNT(*) OVER (PARTITION BY DATE_TRUNC('month', order_date)) AS n
    FROM orders
    GROUP BY DATE_TRUNC('month', order_date), customer_id
)
SELECT
    month,
    SUM((2 * rnk - n - 1) * revenue)::NUMERIC
    / NULLIF(MAX(n) * SUM(revenue), 0) AS gini,
    MAX(n) AS active_customers
FROM ranked
GROUP BY month
ORDER BY month;

Растущий Gini = whales становятся ещё больше, бизнес зависит от хвоста меньше.

Частые ошибки

Ошибка 1. Не отсортировать. Формула предполагает упорядоченность по возрастанию. ROW_NUMBER() OVER (ORDER BY x) обязателен.

Ошибка 2. Включить отрицательные значения. Gini определён для неотрицательных. Refunds дают отрицательную revenue, индекс может выйти за [0,1]. Используйте GREATEST(amount, 0) или фильтр.

Ошибка 3. Маленькая выборка. Для < 30 игроков Gini шумит сильно. Сообщайте количество вместе с метрикой.

Ошибка 4. Сравнивать Gini между сегментами разного размера. Gini зависит от N. Используйте Atkinson или Theil, если нужно строгое сравнение.

Ошибка 5. Интерпретировать «0.4 как у Швеции». Контекст другой. Gini продукта 0.7 не значит, что он «несправедлив» — это норма для consumer apps (whales достаточно типичны).

Связанные темы

FAQ

Gini vs HHI?

HHI чувствителен к топ-игрокам (квадрат долей). Gini — к равномерности всей кривой. Для customer concentration HHI понятнее, для «насколько хвост слабый» — Gini.

Gini для активности?

Да: вместо revenue подставьте actions, sessions, posts. Так смотрят на «сколько % юзеров делает 80% активности».

Какой Gini «нормален»?

Для consumer SaaS — 0.6–0.8. Для B2B с enterprise клиентами — 0.8+. Для гомогенных сегментов (например, все на 1 тарифе) — 0.3–0.5.

Как объяснить продакту?

«Gini 0.7 = top-10% юзеров делают примерно 60% всей выручки». Точнее показывает кривая Лоренца.

Можно ли по событиям?

Да: например, неравенство постов в соцсети, vote-распределение в комьюнити, число сделок у sales-репов.