这一节主要讲分层线性回归与多项式回归模型
1. 分层线性回归
先了解一下什么是分层模型?
以抛硬币问题为例,后验
y
y
y 服从伯努利分布,先验
θ
\theta
θ 服从Beta分布,那么Beta分布的两个参数
α
,
β
\alpha, \beta
α,β 是怎么来的呢?如果给予
α
,
β
\alpha, \beta
α,β 一个新的分布,那么就称这个新的分布为超先验(即更高层的先验)。可以用如下图进行表示:
1.1 非分层模型
案例核心:在组这一层同时对多个组建模并进行估计。
先创建8个相关的数据组(导入的库与第一节基本一样)
N = 20
M = 8
# 生成8组数据,前7组每组20个数据,最后一组一个数据
idx = np.repeat(range(M-1), N)
idx = np.append(idx, 7)
np.random.seed(314)
alpha_real = np.random.normal(2.5, 0.5, size=M)
beta_real = np.random.beta(6, 1, size=M)
eps_real = np.random.normal(0, 0.5, size=len(idx))
y_m = np.zeros(len(idx))
x_m = np.random.normal(10, 1, len(idx))
y_m = alpha_real[idx] + beta_real[idx] * x_m + eps_real
plt.figure(figsize=(10,5))
j, k = 0, N
for i in range(M):
plt.subplot(2,4,i+1)
plt.scatter(x_m[j:k], y_m[j:k])
plt.xlabel('$x_{}$'.format(i), fontsize=16)
plt.ylabel('$y$', fontsize=16, rotation=0)
plt.xlim(6, 15)
plt.ylim(7, 17)
j += N
k += N
plt.tight_layout()
plt.savefig('B04958_04_16.png', dpi=300, figsize=(5.5, 5.5));
在输入到模型之前,先对其进行中心化处理:
x_centered = x_m - x_m.mean()
先用非多层的模型去拟合,基本与上一篇博客处理流程相同:
- 建模;
- 由于对 x x x 进行了中心化,因此需要将 α \alpha α 转换到原始的尺度。
with pm.Model() as unpooled_model:
alpha_tmp = pm.Normal('alpha_tmp', mu=0, sd=10, shape=M)
beta = pm.Normal('beta', mu=0, sd=10, shape=M)
epsilon = pm.HalfCauchy('epsilon', 5)
nu = pm.Exponential('nu', 1/30)
y_pred = pm.StudentT('y_pred', mu= alpha_tmp[idx] + beta[idx] * x_centered, sd=epsilon, nu=nu, observed=y_m)
# 将 alpha 转换到原始的尺度
alpha = pm.Deterministic('alpha', alpha_tmp - beta * x_m.mean())
start = pm.find_MAP()
step = pm.NUTS(scaling=start)
trace_up = pm.sample(2000, step=step, start=start, nchains=1)
varnames=['alpha', 'beta', 'epsilon', 'nu']
pm.traceplot(trace_up, varnames)
plt.savefig('B04958_04_17.png', dpi=300, figsize=(5.5, 5.5));
pm.summary(trace_up, varnames)
从结果中可以看到,除了其中一组
α
,
β
\alpha, \beta
α,β 参数,大多数情况下都很正常。根据迹来看,似乎这一组参数一直在自由移动而没有收敛。显然,用一条唯一的直线去拟合一个点是不适合的。
1.2 分层模型
思考一下如何利用前七组的数据模式合理地拟合第八组中的一个点?
解决这个问题无非有两种方式:
- 给 α \alpha α 加入一个很强的先验;
- 构建多层模型网模型中加入信息(因为多层模型中组与组之间的信息能够共享)。
先看一下分层模型
with pm.Model() as hierarchical_model:
# hyper-priors
alpha_tmp_mu = pm.Normal('alpha_tmp_mu', mu=0, sd=10)
alpha_tmp_sd = pm.HalfNormal('alpha_tmp_sd', 10)
beta_mu = pm.Normal('beta_mu', mu=0, sd=10)
beta_sd = pm.HalfNormal('beta_sd', sd=10)
# a prioris
alpha_tmp = pm.Normal('alpha_tmp', mu=alpha_tmp_mu, sd=alpha_tmp_sd, shape=M)
beta = pm.Normal('beta', mu=beta_mu, sd=beta_sd, shape=M)
epsilon = pm.HalfCauchy('epsilon', 5)
nu = pm.Exponential('nu', 1/30)
y_pred = pm.StudentT('y_pred', mu=alpha_tmp[idx] + beta[idx] * x_centered, sd=epsilon, nu=nu, observed=y_m)
alpha = pm.Deterministic('alpha', alpha_tmp - beta * x_m.mean())
alpha_mu = pm.Deterministic('alpha_mu', alpha_tmp_mu - beta_mu * x_m.mean())
alpha_sd = pm.Deterministic('alpha_sd', alpha_tmp_sd - beta_mu * x_m.mean())
trace_hm = pm.sample(1000, advi_map=True, chains=1, njobs=1)
varnames=['alpha', 'alpha_mu', 'alpha_sd', 'beta', 'beta_mu', 'beta_sd', 'epsilon', 'nu']
pm.traceplot(trace_hm, varnames)
plt.savefig('B04958_04_19.png', dpi=300, figsize=(5.5, 5.5));
将拟合的直线进行可视化,发现那条直线主要收到了其他组数据点的影响
plt.figure(figsize=(10,5))
j, k = 0, N
x_range = np.linspace(x_m.min(), x_m.max(), 10)
for i in range(M):
plt.subplot(2,4,i+1)
plt.scatter(x_m[j:k], y_m[j:k])
plt.xlabel('$x_{}$'.format(i), fontsize=16)
plt.ylabel('$y$', fontsize=16, rotation=0)
alfa_m = trace_hm['alpha'][:,i].mean()
beta_m = trace_hm['beta'][:,i].mean()
plt.plot(x_range, alfa_m + beta_m * x_range, c='k', label='y = {:.2f} + {:.2f} * x'.format(alfa_m, beta_m))
plt.xlim(x_m.min()-1, x_m.max()+1)
plt.ylim(y_m.min()-1, y_m.max()+1)
j += N
k += N
plt.tight_layout()
plt.savefig('B04958_04_20.png', dpi=300, figsize=(5.5, 5.5));
注意:相关性与因果性是不同的概念,相关性只是构建的模型对变量之间的关系进行了数学上的解释,而因果关系是变量之间的物理机制的可信性解释。
2. 多项式回归
多项式回归仍然是线性回归是指模型中的参数是线性组合的。
按照惯例,先生成模拟数据:
ans = sns.load_dataset('anscombe')
x_2 = ans[ans.dataset == 'II']['x'].values
y_2 = ans[ans.dataset == 'II']['y'].values
x_2 = x_2 - x_2.mean()
y_2 = y_2 - y_2.mean()
plt.scatter(x_2, y_2)
plt.xlabel('$x$', fontsize=16)
plt.ylabel('$y$', fontsize=16, rotation=0)
plt.savefig('B04958_04_21.png', dpi=300, figsize=(5.5, 5.5))
建立模型对数据进行拟合
with pm.Model() as model_poly:
alpha = pm.Normal('alpha', mu=0, sd=10)
beta1 = pm.Normal('beta1', mu=0, sd=1)
beta2 = pm.Normal('beta2', mu=0, sd=1)
epsilon = pm.HalfCauchy('epsilon', 5)
mu = alpha + beta1 * x_2 + beta2 * x_2**2
y_pred = pm.Normal('y_pred', mu=mu, sd=epsilon, observed=y_2)
start = pm.find_MAP()
step = pm.NUTS(scaling=start)
trace_poly = pm.sample(2000, step=step, start=start, nchains=1)
pm.traceplot(trace_poly)
plt.savefig('B04958_04_22.png', dpi=300, figsize=(5.5, 5.5))
对最后的拟合结果进行可视化
x_p = np.linspace(-6, 6)
y_p = trace_poly['alpha'].mean() + trace_poly['beta1'].mean() * x_p + trace_poly['beta2'].mean() * x_p**2
plt.scatter(x_2, y_2)
plt.xlabel('$x$', fontsize=16)
plt.ylabel('$y$', fontsize=16, rotation=0)
plt.plot(x_p, y_p, c='r')
plt.savefig('B04958_04_23.png', dpi=300, figsize=(5.5, 5.5))
进一步去思考:
- 在多项式模型中怎么去解释系数?
- 超过 2阶 或 3阶 的多项式模型是否还有足够大的用途?
项目源码:https://github.com/dhuQChen/BayesianAnalysis