loessПреобразование loess в Vega-Lite используется для
построения сглаженной линии тренда на основе метода локально взвешенной
регрессии (Locally Estimated Scatterplot Smoothing). Метод позволяет
выявлять закономерности в шумных данных без необходимости задавать
глобальную математическую модель.
В отличие от линейной регрессии, где строится одна общая функция для всего набора данных, LOESS вычисляет локальные аппроксимации для небольших участков данных и затем объединяет их в плавную кривую.
Типичные сценарии применения:
Алгоритм выполняет несколько этапов:
Для каждой точки выбирается локальное окно соседних значений.
Точкам внутри окна назначаются веса:
На локальном участке строится регрессия.
Полученные локальные оценки объединяются в непрерывную кривую.
Главная особенность метода — отсутствие жёстко заданной формы функции.
LOESS способен описывать:
loessТрансформация подключается через массив transform.
{
transform: [
{
loess: "y",
on: "x"
}
]
}
| Параметр | Описание |
|---|---|
loess |
Поле зависимой переменной |
on |
Поле независимой переменной |
bandwidth |
Размер локального окна |
groupby |
Группировка данных |
as |
Имена выходных полей |
vegaEmbed("#view", {
data: {
values: [
{x: 1, y: 5},
{x: 2, y: 9},
{x: 3, y: 7},
{x: 4, y: 10},
{x: 5, y: 15},
{x: 6, y: 14},
{x: 7, y: 18}
]
},
layer: [
{
mark: "point",
encoding: {
x: {field: "x", type: "quantitative"},
y: {field: "y", type: "quantitative"}
}
},
{
transform: [
{
loess: "y",
on: "x"
}
],
mark: {
type: "line",
color: "red"
},
encoding: {
x: {field: "x", type: "quantitative"},
y: {field: "y", type: "quantitative"}
}
}
]
});
Слой point отображает исходные точки.
Второй слой:
bandwidthbandwidthbandwidth определяет размер локального окна,
используемого для вычисления регрессии.
{
loess: "y",
on: "x",
bandwidth: 0.3
}
Значение находится в диапазоне:
0 < bandwidth <= 1
bandwidthНебольшое значение:
bandwidth: 0.1
Особенности:
bandwidthbandwidth: 0.9
Особенности:
bandwidthvegaEmbed("#view", {
data: {
url: "data/cars.json"
},
layer: [
{
mark: "point",
encoding: {
x: {
field: "Horsepower",
type: "quantitative"
},
y: {
field: "Miles_per_Gallon",
type: "quantitative"
}
}
},
{
transform: [
{
loess: "Miles_per_Gallon",
on: "Horsepower",
bandwidth: 0.2
}
],
mark: {
type: "line",
color: "red"
},
encoding: {
x: {
field: "Horsepower",
type: "quantitative"
},
y: {
field: "Miles_per_Gallon",
type: "quantitative"
}
}
},
{
transform: [
{
loess: "Miles_per_Gallon",
on: "Horsepower",
bandwidth: 0.8
}
],
mark: {
type: "line",
color: "blue"
},
encoding: {
x: {
field: "Horsepower",
type: "quantitative"
},
y: {
field: "Miles_per_Gallon",
type: "quantitative"
}
}
}
]
});
groupbyLOESS может вычисляться отдельно для разных категорий.
{
transform: [
{
loess: "sales",
on: "month",
groupby: ["region"]
}
]
}
Каждая группа:
vegaEmbed("#view", {
data: {
values: [
{month: 1, sales: 10, region: "East"},
{month: 2, sales: 12, region: "East"},
{month: 3, sales: 18, region: "East"},
{month: 1, sales: 8, region: "West"},
{month: 2, sales: 15, region: "West"},
{month: 3, sales: 20, region: "West"}
]
},
transform: [
{
loess: "sales",
on: "month",
groupby: ["region"]
}
],
mark: "line",
encoding: {
x: {
field: "month",
type: "quantitative"
},
y: {
field: "sales",
type: "quantitative"
},
color: {
field: "region",
type: "nominal"
}
}
});
asПо умолчанию Vega-Lite создаёт выходные поля с теми же именами.
Можно переопределить их:
{
loess: "y",
on: "x",
as: ["smoothX", "smoothY"]
}
После трансформации будут созданы:
| Поле | Назначение |
|---|---|
smoothX |
сглаженное значение X |
smoothY |
сглаженное значение Y |
asvegaEmbed("#view", {
data: {
values: [
{x: 1, y: 2},
{x: 2, y: 4},
{x: 3, y: 3},
{x: 4, y: 7}
]
},
transform: [
{
loess: "y",
on: "x",
as: ["lx", "ly"]
}
],
mark: "line",
encoding: {
x: {
field: "lx",
type: "quantitative"
},
y: {
field: "ly",
type: "quantitative"
}
}
});
layerНаиболее распространённый сценарий — отображение:
layer: [
{
mark: "point"
},
{
transform: [
{
loess: "y",
on: "x"
}
],
mark: "line"
}
]
LOESS особенно эффективен для анализа времени.
vegaEmbed("#view", {
data: {
url: "data/seattle-weather.csv"
},
layer: [
{
mark: "point",
encoding: {
x: {
field: "date",
type: "temporal"
},
y: {
field: "temp_max",
type: "quantitative"
}
}
},
{
transform: [
{
loess: "temp_max",
on: "date",
bandwidth: 0.3
}
],
mark: {
type: "line",
color: "red",
size: 3
},
encoding: {
x: {
field: "date",
type: "temporal"
},
y: {
field: "temp_max",
type: "quantitative"
}
}
}
]
});
Предполагает наличие общей функции:
genui{“math_block_widget_always_prefetch_v2”:{“content”:“y=ax+b”}}
Особенности:
Не требует единой функции.
Особенности:
Скользящее среднее:
LOESS:
LOESS является вычислительно затратным методом.
Особенно при:
bandwidth;transform: [
{
sample: 1000
},
{
loess: "y",
on: "x"
}
]
transform: [
{
aggregate: [
{
op: "mean",
field: "value",
as: "avg"
}
],
groupby: ["date"]
},
{
loess: "avg",
on: "date"
}
]
bandwidthbandwidth: 0.01
Результат:
bandwidth: 1
Результат:
LOESS плохо работает:
vegaEmbed("#view", {
data: {
values: [
{day: 1, sales: 120},
{day: 2, sales: 135},
{day: 3, sales: 128},
{day: 4, sales: 170},
{day: 5, sales: 180},
{day: 6, sales: 175},
{day: 7, sales: 220},
{day: 8, sales: 210},
{day: 9, sales: 230}
]
},
layer: [
{
mark: {
type: "line",
color: "#999"
},
encoding: {
x: {
field: "day",
type: "quantitative"
},
y: {
field: "sales",
type: "quantitative"
}
}
},
{
transform: [
{
loess: "sales",
on: "day",
bandwidth: 0.4
}
],
mark: {
type: "line",
color: "red",
size: 4
},
encoding: {
x: {
field: "day",
type: "quantitative"
},
y: {
field: "sales",
type: "quantitative"
}
}
}
]
});
В чистом Vega трансформация выглядит иначе.
{
"type": "loess",
"x": "x",
"y": "y",
"bandwidth": 0.3
}
Преимущества:
Преимущества:
Метод особенно полезен при:
Метод плохо подходит для:
Без точек сглаженная линия может вводить в заблуждение.
Правильный подход:
layer: [
{ mark: "point" },
{ mark: "line" }
]
mark: {
type: "line",
size: 4,
color: "red"
}
mark: {
type: "point",
opacity: 0.3
}
Это помогает:
LOESS можно сочетать с:
params);selection).transform: [
{
filter: "datum.value > 0"
},
{
loess: "value",
on: "date"
}
]
Порядок имеет значение.
transform: [
{ filter: "datum.y != null" },
{ calculate: "datum.y * 2", as: "newY" },
{ loess: "newY", on: "x" }
]
LOESS будет работать уже с преобразованными данными.
LOESS часто комбинируется с:
| Transform | Назначение |
|---|---|
filter |
очистка данных |
calculate |
вычисление полей |
aggregate |
агрегация |
window |
оконные вычисления |
sample |
уменьшение выборки |
lookup |
объединение таблиц |
При некорректном результате следует проверить:
null;bandwidth.Правильный вариант:
x: {
field: "date",
type: "temporal"
}
Неправильный:
x: {
field: "date",
type: "nominal"
}
transform: [
{
filter: "datum.y != null"
},
{
loess: "y",
on: "x"
}
]
vegaEmbed("#view", {
data: {
url: "data.csv"
},
layer: [
{
mark: "point",
encoding: {
x: {
field: "x",
type: "quantitative"
},
y: {
field: "y",
type: "quantitative"
}
}
},
{
transform: [
{
loess: "y",
on: "x",
bandwidth: 0.4
}
],
mark: {
type: "line",
color: "red",
size: 3
},
encoding: {
x: {
field: "x",
type: "quantitative"
},
y: {
field: "y",
type: "quantitative"
}
}
}
]
});