Цепочки трансформаций

Модель обработки данных как последовательность шагов

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

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

Основные свойства цепочек трансформаций:

  • последовательное выполнение шагов обработки данных
  • неизменяемость промежуточных наборов (каждый шаг формирует новый поток)
  • декларативное описание вместо императивных вычислений
  • тесная связь трансформаций с визуальными каналами (encoding)

Позиция трансформаций в архитектуре Vega-Lite

В Vega-Lite трансформации задаются внутри поля transform и располагаются до этапа кодирования (encoding). Общая схема обработки выглядит следующим образом:

  1. загрузка данных (data)
  2. последовательные трансформации (transform)
  3. группировка и агрегации (если указаны)
  4. визуальное кодирование (encoding)
  5. отрисовка графического примитива

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

Пример базовой структуры:

{
  "data": {"url": "data.csv"},
  "transform": [
    {"filter": "datum.value > 10"},
    {"calculate": "datum.value * 2", "as": "scaled"}
  ],
  "mark": "line",
  "encoding": {
    "x": {"field": "date", "type": "temporal"},
    "y": {"field": "scaled", "type": "quantitative"}
  }
}

Принцип последовательного выполнения

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

Существенные последствия такой модели:

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

Пример влияния порядка:

"transform": [
  {"calculate": "datum.a + datum.b", "as": "sum"},
  {"filter": "datum.sum > 100"}
]

и обратный порядок:

"transform": [
  {"filter": "datum.a + datum.b > 100"},
  {"calculate": "datum.a + datum.b", "as": "sum"}
]

Оба варианта логически различны по производительности и иногда по результату, особенно при работе с производными полями.


Основные типы трансформаций

Фильтрация данных

Трансформация filter ограничивает поток данных по логическому условию. Это один из наиболее ранних этапов цепочки, часто используемый для уменьшения объёма данных перед более дорогими операциями.

{"filter": "datum.price > 50"}

Фильтрация влияет на все последующие шаги, включая агрегации и построение шкал.


Вычисляемые поля

Трансформация calculate создаёт новые поля на основе выражений. Она расширяет структуру данных без изменения исходных полей.

{"calculate": "datum.sales * 1.2", "as": "adjusted_sales"}

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


Агрегация

Трансформация aggregate выполняет группировку и свёртку данных. Она является одной из ключевых операций для построения диаграмм с обобщёнными значениями.

{
  "aggregate": [
    {"op": "mean", "field": "value", "as": "avg_value"}
  ],
  "groupby": ["category"]
}

Агрегация радикально изменяет структуру данных: множество строк заменяется группами.

Влияние на цепочку:

  • все последующие трансформации работают уже с агрегированными данными
  • исходные строки становятся недоступными

Биннинг (разбиение диапазонов)

Трансформация bin используется для дискретизации непрерывных значений.

{
  "bin": true,
  "field": "age",
  "as": "age_bin"
}

Биннинг часто применяется перед агрегацией, формируя категории из числовых значений.


Временные преобразования

timeUnit выполняет группировку временных значений по календарным интервалам.

{
  "timeUnit": "month",
  "field": "date",
  "as": "month"
}

Такие преобразования часто выступают промежуточным шагом перед агрегацией или построением временных рядов.


Оконные функции

Трансформация window позволяет вычислять скользящие агрегаты, ранжирование и накопительные суммы.

{
  "window": [
    {"op": "sum", "field": "value", "as": "running_total"}
  ],
  "sort": [{"field": "date"}]
}

Оконные функции зависят от порядка сортировки, что делает их чувствительными к структуре цепочки.


Объединение данных (lookup)

Трансформация lookup используется для соединения двух наборов данных по ключу.

{
  "lookup": "key",
  "from": {
    "data": {"url": "other.csv"},
    "key": "id",
    "fields": ["category"]
  }
}

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


Разворачивание и нормализация структуры

fold преобразует широкий формат данных в длинный, создавая пары ключ-значение.

{
  "fold": ["a", "b", "c"],
  "as": ["key", "value"]
}

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


Композиция трансформаций

Цепочки трансформаций часто представляют собой комбинацию нескольких типов операций. На практике формируются типовые паттерны:

Очистка → вычисление → агрегация

"transform": [
  {"filter": "datum.value != null"},
  {"calculate": "datum.value * 100", "as": "scaled"},
  {
    "aggregate": [
      {"op": "mean", "field": "scaled", "as": "avg"}
    ],
    "groupby": ["category"]
  }
]

Биннинг → агрегация → сортировка

"transform": [
  {"bin": true, "field": "x", "as": "x_bin"},
  {
    "aggregate": [
      {"op": "count", "as": "count"}
    ],
    "groupby": ["x_bin"]
  },
  {"calculate": "datum.count", "as": "y"}
]

Взаимодействие трансформаций и encoding

Результат цепочки трансформаций напрямую определяет доступные поля для визуального кодирования. После выполнения всех шагов:

  • новые поля становятся частью схемы данных
  • агрегированные значения заменяют исходные
  • вычисляемые значения могут использоваться как каналы визуализации

Пример зависимости:

"transform": [
  {"calculate": "datum.sales - datum.expenses", "as": "profit"}
],
"encoding": {
  "y": {"field": "profit", "type": "quantitative"}
}

Отличия Vega и Vega-Lite в реализации цепочек

Vega-Lite

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

Vega

  • граф потока данных (dataflow graph)
  • трансформации представлены как узлы
  • более гибкое управление зависимостями
  • возможность сложных ветвлений и параллельных потоков

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


Оптимизация выполнения цепочек

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

  • ранняя фильтрация уменьшает объём данных для последующих операций
  • агрегации существенно сокращают размер потока
  • lookup-операции могут быть узким местом при больших справочниках
  • window-функции требуют сортировки, что увеличивает стоимость

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


Типовые ошибки построения цепочек

  • размещение calculate после aggregate, когда требуется доступ к исходным строкам
  • использование window без явной сортировки
  • применение bin после агрегации вместо до неё
  • избыточные lookup-операции внутри длинных цепочек
  • фильтрация слишком поздно, после тяжёлых вычислений

Семантика неизменяемости данных

Каждая трансформация не модифицирует входной поток, а создаёт новый. Это поведение формирует предсказуемую модель вычислений, в которой:

  • нет побочных эффектов
  • каждый шаг можно рассматривать изолированно
  • повторное использование данных требует явного дублирования источников

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