groupby совместно с aggregate

Операции groupby и aggregate в Vega-Lite представляют собой основу трансформаций данных, позволяя выполнять группировку записей и вычисление сводных показателей непосредственно на уровне спецификации визуализации. Эти механизмы во многом повторяют логику SQL-оператора GROUP BY, но встроены в декларативную модель описания графиков.

Группировка в Vega-Lite задаётся через массив полей groupby. Каждое уникальное сочетание значений этих полей формирует отдельную группу, внутри которой могут вычисляться агрегаты.

Базовая логика:

  • данные разбиваются на группы по указанным ключам;
  • внутри каждой группы применяются агрегатные функции;
  • результатом становится сокращённый набор данных, пригодный для визуализации.

Группировка не изменяет исходные данные, а создаёт производную таблицу трансформации.

Базовая структура transform с aggregate

В Vega-Lite агрегирование задаётся через блок transform:

{
  "transform": [
    {
      "aggregate": [
        {
          "op": "sum",
          "field": "value",
          "as": "total"
        }
      ],
      "groupby": ["category"]
    }
  ]
}

Здесь:

  • op — операция агрегирования (sum, mean, count, min, max и др.);
  • field — поле исходных данных;
  • as — имя нового поля результата;
  • groupby — ключ группировки.

Результат: каждая категория получает сумму значений value.

Несколько агрегатных функций в одной группе

Vega-Lite позволяет применять несколько агрегатов одновременно внутри одной группировки:

{
  "transform": [
    {
      "aggregate": [
        { "op": "sum", "field": "sales", "as": "total_sales" },
        { "op": "mean", "field": "sales", "as": "avg_sales" },
        { "op": "count", "as": "count_records" }
      ],
      "groupby": ["region"]
    }
  ]
}

В этом случае каждая группа region получает сразу несколько метрик:

  • суммарные продажи;
  • среднее значение;
  • количество записей.

Особенность count: поле field не требуется, так как считается количество строк.

Поведение groupby с несколькими полями

Группировка может быть многомерной:

{
  "transform": [
    {
      "aggregate": [
        { "op": "sum", "field": "profit", "as": "profit_sum" }
      ],
      "groupby": ["country", "year"]
    }
  ]
}

Здесь формируются группы вида:

  • (Germany, 2023)
  • (Germany, 2024)
  • (France, 2023)

Каждая комбинация ключей становится отдельной записью результата.

Это эквивалентно SQL:

SEL ECT country, year, SUM(profit)
FR OM table
GROUP BY country, year;

Использование aggregate без groupby

Если groupby не задан, агрегирование выполняется по всей таблице как по одной группе:

{
  "transform": [
    {
      "aggregate": [
        { "op": "mean", "field": "score", "as": "avg_score" }
      ]
    }
  ]
}

Результат — одна строка с агрегированным значением.

Такой режим часто используется для вычисления глобальных показателей: средних значений, сумм, общего количества записей.

Сортировка агрегированных данных

После группировки часто требуется упорядочивание результата. В Vega-Lite это делается через sort на уровне визуализации или через дополнительный трансформ.

Пример подготовки данных:

{
  "transform": [
    {
      "aggregate": [
        { "op": "sum", "field": "revenue", "as": "revenue_sum" }
      ],
      "groupby": ["product"]
    },
    {
      "calculate": "datum.revenue_sum",
      "as": "metric"
    }
  ]
}

Далее сортировка может применяться в encoding:

"sort": "-y"

Взаимодействие aggregate и calculate

Частая комбинация — сначала группировка, затем вычисление производных метрик:

{
  "transform": [
    {
      "aggregate": [
        { "op": "sum", "field": "sales", "as": "total_sales" }
      ],
      "groupby": ["category"]
    },
    {
      "calculate": "datum.total_sales * 0.1",
      "as": "tax"
    }
  ]
}

Здесь calculate работает уже с результатами агрегирования, а не с исходными данными.

Типичные агрегатные операции

Поддерживаемый набор операций охватывает стандартные статистические функции:

  • sum — сумма значений;
  • mean — среднее арифметическое;
  • median — медиана;
  • min / max — минимальное и максимальное значение;
  • count — количество записей;
  • valid — количество ненулевых значений;
  • distinct — количество уникальных значений;
  • stdev / stdevp — стандартное отклонение;
  • variance / variancep — дисперсия.

Эти операции позволяют строить как простые, так и статистически насыщенные представления данных.

Использование в визуализациях

Наиболее частый сценарий — подготовка данных для столбчатых диаграмм.

Пример: сумма продаж по категориям

{
  "data": { "url": "data/sales.json" },
  "transform": [
    {
      "aggregate": [
        { "op": "sum", "field": "sales", "as": "total_sales" }
      ],
      "groupby": ["category"]
    }
  ],
  "mark": "bar",
  "encoding": {
    "x": { "field": "category", "type": "nominal" },
    "y": { "field": "total_sales", "type": "quantitative" }
  }
}

Здесь агрегирование становится частью конвейера данных, а не отдельной процедурой.

Множественные уровни агрегации

Хотя Vega-Lite не поддерживает вложенные aggregate напрямую, подобный эффект достигается последовательными transform-операциями:

{
  "transform": [
    {
      "aggregate": [
        { "op": "sum", "field": "sales", "as": "sales_sum" }
      ],
      "groupby": ["region", "category"]
    },
    {
      "aggregate": [
        { "op": "mean", "field": "sales_sum", "as": "avg_region_sales" }
      ],
      "groupby": ["region"]
    }
  ]
}

Первая стадия формирует детализацию, вторая — сводит её на уровень региона.

Особенности работы с отсутствующими значениями

При агрегации важно учитывать поведение null:

  • большинство операций игнорируют null;
  • count учитывает строки, но не значения;
  • valid специально предназначен для подсчёта непустых значений.

Это влияет на итоговые показатели, особенно при неполных данных.

Различие между Vega и Vega-Lite

В Vega-Lite агрегирование задаётся декларативно через transform.aggregate, тогда как в Vega (низкоуровневом языке) используется объект aggregate внутри data.transform с более гибкими возможностями.

Vega пример:

{
  "type": "aggregate",
  "groupby": ["category"],
  "ops": ["sum", "mean"],
  "fields": ["value", "value"],
  "as": ["sum_value", "mean_value"]
}

Vega-Lite, в свою очередь, использует более структурированный и читаемый формат массива объектов.

Комбинация с фильтрацией

Перед группировкой часто применяется фильтрация:

{
  "transform": [
    {
      "filter": "datum.sales > 0"
    },
    {
      "aggregate": [
        { "op": "sum", "field": "sales", "as": "positive_sales" }
      ],
      "groupby": ["category"]
    }
  ]
}

Это позволяет исключить нерелевантные данные до выполнения сводных операций.

Практическая роль в аналитических пайплайнах

Связка groupby + aggregate формирует основу большинства аналитических представлений:

  • построение сводных таблиц;
  • агрегация временных рядов;
  • расчёт KPI по сегментам;
  • подготовка данных для визуальных сравнений.

В Vega-Lite эта логика встроена в декларативную модель, что позволяет избегать внешней предобработки данных и держать всю трансформационную цепочку внутри спецификации визуализации.