fold: перевод широкого формата в длинный

Визуализация данных в Vega и Vega-Lite часто начинается с вопроса формы данных. Одна из ключевых операций подготовки — преобразование «широкого» набора столбцов в «длинный» формат. Для этого используется трансформация fold, которая выполняет функцию, аналогичную unpivot в SQL или melt в pandas.


Сущность wide и long форматов

Широкий формат (wide) представляет каждую категорию как отдельный столбец:

месяц продажи_A продажи_B продажи_C
Jan 10 15 8
Feb 12 18 9

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

Длинный формат (long) объединяет категории в строки:

месяц тип значение
Jan продажи_A 10
Jan продажи_B 15
Jan продажи_C 8

Именно такой формат является нативным для большинства визуальных encodings Vega-Lite: color, detail, shape, facet.


Назначение fold

Трансформация fold преобразует набор столбцов в пары:

  • имя исходного столбца → ключ
  • значение ячейки → значение

Это делает возможным:

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

Синтаксис fold в Vega-Lite

{
  "transform": [
    {
      "fold": ["sales_A", "sales_B", "sales_C"],
      "as": ["category", "value"]
    }
  ]
}

Параметры

  • fold — массив имён столбцов, которые будут преобразованы

  • as — массив из двух элементов:

    • имя нового столбца для ключа (название категории)
    • имя нового столбца для значения

Пример полного Vega-Lite spec

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {"month": "Jan", "A": 10, "B": 15, "C": 8},
      {"month": "Feb", "A": 12, "B": 18, "C": 9}
    ]
  },
  "transform": [
    {
      "fold": ["A", "B", "C"],
      "as": ["series", "value"]
    }
  ],
  "mark": "line",
  "encoding": {
    "x": {"field": "month", "type": "ordinal"},
    "y": {"field": "value", "type": "quantitative"},
    "color": {"field": "series", "type": "nominal"}
  }
}

Здесь fold создаёт нормализованную структуру, позволяющую отрисовать несколько линий через одну шкалу y.


Как fold изменяет поток данных

Исходные данные проходят трансформацию:

  1. Каждая строка исходного набора дублируется по числу указанных столбцов
  2. Имя каждого столбца записывается в поле as[0]
  3. Значение ячейки записывается в поле as[1]
  4. Оригинальные «широкие» столбцы исключаются из результата

Результат становится пригодным для унифицированных encoding-каналов.


Типовые сценарии применения

Многосерийные графики

Когда каждая колонка — это отдельный показатель:

  • температура по городам
  • продажи по продуктам
  • метрики по сервисам

fold позволяет превратить их в одну ось значений с разделением через color или detail.


Гибкая визуализация без предобработки

Без fold пришлось бы:

  • вручную преобразовывать данные
  • создавать отдельные datasets
  • дублировать спецификации визуализации

fold устраняет необходимость в предварительном ETL-слое.


Работа с динамическими наборами столбцов

Если структура данных неизвестна заранее, fold может использоваться вместе с вычисляемыми списками полей (в Vega через expression или data join), что позволяет строить универсальные графики.


Сравнение с melt / unpivot

Инструмент Операция
pandas melt wide → long
SQL UNPIVOT wide → long
Vega fold wide → long

fold концептуально является декларативным аналогом этих операций внутри графического pipeline.


Особенности поведения

1. Потеря исходных колонок

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


2. Дублирование строк

Каждая исходная строка превращается в N строк, где N — количество folded-полей.


3. Типы данных

  • ключ (as[0]) всегда строковый
  • значение (as[1]) сохраняет исходный тип, но может приводиться в процессе агрегации

Использование вместе с агрегаторами

fold часто комбинируется с aggregate:

{
  "transform": [
    {
      "fold": ["A", "B", "C"],
      "as": ["series", "value"]
    },
    {
      "aggregate": [
        {"op": "mean", "field": "value", "as": "avg"}
      ],
      "groupby": ["series"]
    }
  ]
}

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


Влияние на encodings

После fold новые поля становятся стандартными каналами Vega-Lite:

  • color: series → разделение линий или баров
  • x: category → категориальная ось
  • y: value → количественная ось

Таким образом fold выступает как мост между структурой данных и визуальной моделью.


Ограничения подхода

fold эффективно работает при следующих условиях:

  • количество колонок известно или контролируемо
  • структура «wide» действительно содержит повторяющиеся типы данных

Однако он менее удобен, если:

  • данные уже в long формате
  • требуется сложная иерархия полей
  • присутствует вложенная структура (для этого используются flatten, join или lookup)

Внутренняя логика в Vega pipeline

fold выполняется на этапе трансформаций до encoding. Это означает:

  1. загрузка данных
  2. применение transform (включая fold)
  3. вычисление производных полей
  4. построение визуальных каналов

Порядок важен, поскольку последующие шаги уже не «знают» о широком формате.


Практическая роль в архитектуре визуализаций

fold часто выступает как точка нормализации данных внутри декларативной модели:

  • упрощает спецификации
  • уменьшает количество datasets
  • делает визуализацию более композиционной

В сложных dashboard-конфигурациях fold становится стандартным способом унификации метрик разного происхождения в одном графике.