Это будет короткий пост, потому что знаете что? Вот только не надо, чтобы он был длинным. Иногда нужно просто что-то увидеть, и ты сразу это понимаешь.

Иногда ваши данные гетероскедастичны, и вы не хотите делать глупости, чтобы с этим справиться. Байесовские методы спасают в обоих случаях.

Гетероскедастичность — это, в основном, когда дисперсия вашей целевой переменной отличается для заданных значений ваших данных. Или, выражаясь более математически, дисперсия y зависит от x.

Сначала давайте создадим несколько поддельных данных, чтобы вы знали, с чем мы имеем дело.

Код стандартной линейной модели в PyMC3 приведен ниже, и он будет эталоном.

with pm.Model() as simple_model:
    # Priors
    m = pm.Normal('m', mu=0, sd=100**2)
    b = pm.Normal('b', mu=0, sd=100**2)
    sig = pm.HalfNormal('sigma', sd=100**2)
    
    # Likelihood    
    rsq = pm.Deterministic('rsq', r2_pymc3(y, m*x + b))
    
    obs = pm.Normal('y', mu=m*x + b, sd=sig, observed=y)
    
    trace_simple_model = pm.sample(2000)
    
    pm.traceplot(trace_simple_model)
    graph.show()

На самом деле имеет дело с гетероскедастичностью

Метод 1. Коши как функция правдоподобия

# Method 1. Cauchy Method
with pm.Model() as cauchy_model:
    # Priors
    m = pm.Normal('m', mu=0, sd=100**2)
    b = pm.Normal('b', mu=0, sd=100**2)
    sig = pm.HalfNormal('sigma', sd=100**2)
    
    # Likelihood    
    rsq = pm.Deterministic('rsq', r2_pymc3(y, m*x + b))
    
    obs = pm.Cauchy('y', alpha=m*x + b, beta=sig, observed=y)
    
    trace_cauchy_model = pm.sample(2000)
    
    pm.traceplot(trace_cauchy_model)
    graph.show()

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

Метод 2. Моделирование дисперсии по данным

# Method 2. modeling 
with pm.Model() as fancy_model:
    n_samples = len(y)
    data, target = x, y
    
    # Priors
    m = pm.Normal('m', mu=0, sd=100**2)
    b = pm.Normal('b', mu=0, sd=100**2)
    
    sig_m = pm.Normal('sigma_m', mu=0, sd=100**2)
    sig_b = pm.Normal('sigma_b', mu=0, sd=100**2)
    sig_given_data = pm.Deterministic('sig', pm.math.log(1 + pm.math.exp(sig_m * data + sig_b)))
    
    # Likelihood    
    rsq = pm.Deterministic('rsq', r2_pymc3(y, m*x + b))
    
    obs = pm.Normal('y', mu=m*data + b, sd=sig_given_data, observed=target)
    
    trace_fancy_model = pm.sample(2000)
    
    pm.traceplot(trace_fancy_model)
    graph.show()

Обратите внимание, что дисперсия m и b все еще более узкая, чем в обычной байесовской регрессии. Однако, в отличие от распределения Коши, наклон и точка пересечения оцениваются лучше.

Вывод

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

Полный и более подробный блокнот Jupyter можно найти здесь.