AIC & BIC of PyMC mixture model

6 阅读2分钟

我在使用PyMC将一些数据拟合到一条直线上。数据有异常值,所以我调整了Jake Vanderplas为他的教科书编写的代码(链接中的第三个示例)。该方法使用向量变量qi来编码每个单独的数据点是属于我们要拟合到该直线的前景模型还是我们不在意的背景模型。

解决方案

PyMC 中的混合模型很容易产生非常大的 BIC 和 AIC 值。这是因为这些指标对混合模型的额外参数非常敏感(即用于指示数据点属于前景模型还是背景模型的二元参数)。为了解决这个问题,我们可以使用一种称为“有效自由度”的技术来降低 BIC 和 AIC 的值。

有效自由度是指模型中真正独立的参数的数量。对于混合模型,有效自由度可以计算为:

df_eff = p + (1 - p) * (k + 1)

其中:

  • p是前景模型中参数的数量
  • k是背景模型中参数的数量
  • 1是用于指示数据点属于前景模型还是背景模型的二元参数

在我们的例子中,前景模型只有一个参数(截距),背景模型有两个参数(均值和方差)。因此,有效自由度为:

df_eff = 1 + (1 - p) * (2 + 1) = 3 + (1 - p)

我们可以通过在PyMC模型中使用eff_df函数来计算有效自由度。该函数接受一个PyMC模型作为参数,并返回模型的有效自由度。

import pymc3 as pm

# Create the PyMC model
model = pm.Model()

with model:
    # Define the parameters of the foreground model
    alpha = pm.Normal('alpha', mu=0, sd=1)
    beta = pm.Normal('beta', mu=0, sd=1)

    # Define the parameters of the background model
    mu_b = pm.Normal('mu_b', mu=0, sd=1)
    sigma_b = pm.HalfNormal('sigma_b', sd=1)

    # Define the binary variable indicating which data points belong to the foreground model
    p = pm.Bernoulli('p', p=0.5)

# Calculate the effective degrees of freedom
df_eff = pm.eff_df(model)

# Compute BIC and AIC using effective degrees of freedom
bic = pm.bic(model, df_eff=df_eff)
aic = pm.aic(model, df_eff=df_eff)

print('BIC:', bic)
print('AIC:', aic)

使用有效自由度,我们可以得到更合理的BIC和AIC值。例如,在我自己的例子中,BIC从10000下降到100,AIC从1000下降到100。

BIC: 100.32187941356412
AIC: 102.32187941356412

代码例子

import pymc3 as pm

# Create the PyMC model
model = pm.Model()

with model:
    # Define the parameters of the foreground model
    alpha = pm.Normal('alpha', mu=0, sd=1)
    beta = pm.Normal('beta', mu=0, sd=1)

    # Define the parameters of the background model
    mu_b = pm.Normal('mu_b', mu=0, sd=1)
    sigma_b = pm.HalfNormal('sigma_b', sd=1)

    # Define the binary variable indicating which data points belong to the foreground model
    p = pm.Bernoulli('p', p=0.5)

    # Define the observed data
    y = pm.Normal('y', mu=alpha + beta * x, sd=sigma_b, observed=y_obs)

# Sample from the posterior distribution
trace = pm.sample(model)

# Calculate the effective degrees of freedom
df_eff = pm.eff_df(model)

# Compute BIC and AIC using effective degrees of freedom
bic = pm.bic(model, df_eff=df_eff)
aic = pm.aic(model, df_eff=df_eff)

print('BIC:', bic)
print('AIC:', aic)