Как посчитать heteroscedasticity в SQL
Содержание:
Зачем проверять
OLS предполагает homoscedasticity — постоянная дисперсия residuals по всем x. Если дисперсия растёт (revenue: при больших значениях разброс больше) — оценки коэффициентов остаются unbiased, но standard errors неверны. Доверительные интервалы и p-values становятся неточными.
Простой groupby тест
Разделим x на бакеты, посмотрим дисперсию residuals в каждом:
WITH residuals AS (
SELECT
x,
y - (REGR_INTERCEPT(y, x) OVER () + REGR_SLOPE(y, x) OVER () * x) AS residual
FROM training_data
),
buckets AS (
SELECT
NTILE(10) OVER (ORDER BY x) AS bucket,
x,
residual
FROM residuals
)
SELECT
bucket,
COUNT(*) AS n,
AVG(x) AS mean_x,
VAR_SAMP(residual) AS var_residual,
STDDEV_SAMP(residual) AS std_residual
FROM buckets
GROUP BY bucket
ORDER BY bucket;Если std_residual стабилен по бакетам — homoscedastic. Если растёт (бакеты с большими x — больше variance) — heteroscedastic.
Breusch-Pagan в SQL
Идея: регрессируем residual² на x. Если slope != 0 — heteroscedasticity.
WITH residuals AS (
SELECT
x,
POWER(y - (REGR_INTERCEPT(y, x) OVER () + REGR_SLOPE(y, x) OVER () * x), 2) AS sq_residual
FROM training_data
)
SELECT
REGR_SLOPE(sq_residual, x) AS slope_on_squared,
REGR_R2(sq_residual, x) AS r2_of_aux_regression,
COUNT(*) * REGR_R2(sq_residual, x) AS bp_statistic,
COUNT(*) AS n
FROM residuals;bp_statistic распределена как chi-square(1). p < 0.05 — отвергаем homoscedasticity. Точные критические values: 3.84 (α=0.05), 6.63 (α=0.01).
Что делать с heteroscedasticity
Несколько подходов:
- Robust standard errors — Huber-White (HC0-HC3). Невозможно в чистом SQL, делают в Python.
- Log-transform —
LN(y)часто стабилизирует variance. - Weighted least squares — веса обратные variance.
- Просто сообщить: если bias estimates маленький, p-value скорректировать через bootstrap.
В SQL чаще всего — log-transform:
SELECT
REGR_SLOPE(LN(y), x) AS log_slope,
REGR_INTERCEPT(LN(y), x) AS log_intercept
FROM training_data
WHERE y > 0;По графику residuals
В дашборде имеет смысл показать residuals vs predicted:
WITH model AS (
SELECT
REGR_SLOPE(y, x) AS slope,
REGR_INTERCEPT(y, x) AS intercept
FROM training_data
),
diag AS (
SELECT
m.intercept + m.slope * d.x AS predicted,
d.y - (m.intercept + m.slope * d.x) AS residual
FROM training_data d
CROSS JOIN model m
)
SELECT *
FROM diag;Экспортируйте в дашборд, посмотрите «funnel»: расширяющаяся форма = heteroscedasticity.
Частые ошибки
Ошибка 1. Breusch-Pagan на multivariate без всех predictor variables. В строгой версии регрессируете residual² на ВСЕ x. В SQL bivariate проще, но даёт неполную картину.
Ошибка 2. Считать homoscedasticity на in-sample residuals. Если outliers повлияли на обучение, residuals искусственно гладкие. Лучше on test или CV-residuals.
Ошибка 3. Игнорировать log-transform для revenue/sessions. Эти метрики почти всегда heteroscedastic. Log-transform решает.
Ошибка 4. Делать вывод только по bucketing. Bucketing может скрыть pattern. Используйте формальный тест.
Ошибка 5. Не отчитываться о выборе SE. В отчёте — какие SE используете (OLS / robust / cluster). Иначе p-values несравнимы.
Связанные темы
- Как посчитать linear regression в SQL
- Как посчитать residuals в SQL
- Как посчитать r2 в SQL
- Как посчитать z-score outliers в SQL
FAQ
Heteroscedasticity ломает OLS?
Делает SE неверными. Coefficient estimates still unbiased.
Какой p в Breusch-Pagan?
< 0.05 — отвергаем homoscedasticity. На больших N тест почти всегда отвергает.
Log-transform — всегда работает?
Часто, но не всегда. Box-Cox более общий.
Robust SE в Postgres?
Нет встроенных. Через Python.
Heteroscedasticity и outliers — одно?
Нет. Outliers — отдельные точки. Heteroscedasticity — структурное свойство дисперсии.