具有对数正态响应 PYMC3 的线性回归
Linear Regression with Lognormal Response PYMC3
这是我第一次尝试为对数正态分布的响应建模线性回归。
我有一个包含两个变量的数据框 df
:预测变量 X
和响应。
当我绘制 response
与预测变量 X
的关系时,我们得到了这个漂亮的图:
当我绘制响应的对数分布时 np.log(response)
我得到了一些非常接近正态分布的东西:
。
为了模拟 X
和 response
之间的关系,我构建了以下模型,
import pymc3 as pm
with pm.Model() as model:
a = pm.Normal('a', 0, 10)
b = pm.Normal('b', 0, 10)
sigma = pm.Uniform('sigma', lower=0, upper=10)
mu = pm.Deterministic('mu', a + b * df_train[X])
y_hat = pm.Lognormal('y_hat', mu = mu, sd = sigma, observed = df['response'] )
trace = pm.sample(2000, tune = 2000)
下一步是测量模型的正确扩展程度,因此我计算数据集的平均响应,即
mu_hat = np.exp(trace['mu'].mean(0)
但是,当我绘制这个平均值与测试集的拟合程度时,我发现拟合度很差:
可能的解决方案:我已经尝试了其他可能性,例如正态和泊松,但我无法实现模型的收敛。我收到一条错误消息:
Bad initial energy: inf. The model might be misspecified
.
关于为什么这次合身如此惨败有什么想法吗?
看起来您的 X 呈对数正态分布,具有线性响应,并且 X 的大小可能存在一些线性误差。没有数据,很难判断,但这是我对您的问题的再现:
matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
x = np.random.lognormal(5, 1, 10000)
y = x * np.random.normal(5,1,10000)
f, axes = plt.subplots(2, 1, figsize=(16,12))
sns.scatterplot(x,y, ax=axes[0])
sns.distplot(np.log(y), ax=axes[1])
Scatterplot of x and y, distribution of log(y)
然后我们可以对 x 系数和相关 y 误差建模:
with pm.Model() as model:
sigma = pm.InverseGamma('sigma', mu=(y/x).std(), sd = (y/x).std()/len(x))
#intercept = pm.Normal('Intercept', 0, sigma=1)
x_coeff = pm.Normal('x_coeff', (y/x).mean(), sigma=1)
l = pm.Normal('l', mu=x_coeff, sigma=sigma, observed=y/x)
trace = pm.sample(3000, tune=1000, cores=4)
现在绘制我们得到的线:
f, axes = plt.subplots(figsize=(16,8))
sns.scatterplot(x, y, ax=axes)
for (_,val) in pm.stats.quantiles(trace['x_coeff']).items():
plt.plot(x, val*x, color='b')
for (__, sd) in pm.stats.quantiles(trace['sigma']).items():
plt.plot(x, (val+2*sd)*x, color='r')
plt.plot(x, (val-2*sd)*x, color='r')
x coefficients plotted with 2*sd positive and negative
这是我第一次尝试为对数正态分布的响应建模线性回归。
我有一个包含两个变量的数据框 df
:预测变量 X
和响应。
当我绘制 response
与预测变量 X
的关系时,我们得到了这个漂亮的图:
当我绘制响应的对数分布时 np.log(response)
我得到了一些非常接近正态分布的东西:
。
为了模拟 X
和 response
之间的关系,我构建了以下模型,
import pymc3 as pm
with pm.Model() as model:
a = pm.Normal('a', 0, 10)
b = pm.Normal('b', 0, 10)
sigma = pm.Uniform('sigma', lower=0, upper=10)
mu = pm.Deterministic('mu', a + b * df_train[X])
y_hat = pm.Lognormal('y_hat', mu = mu, sd = sigma, observed = df['response'] )
trace = pm.sample(2000, tune = 2000)
下一步是测量模型的正确扩展程度,因此我计算数据集的平均响应,即
mu_hat = np.exp(trace['mu'].mean(0)
但是,当我绘制这个平均值与测试集的拟合程度时,我发现拟合度很差:
可能的解决方案:我已经尝试了其他可能性,例如正态和泊松,但我无法实现模型的收敛。我收到一条错误消息:
Bad initial energy: inf. The model might be misspecified
.
关于为什么这次合身如此惨败有什么想法吗?
看起来您的 X 呈对数正态分布,具有线性响应,并且 X 的大小可能存在一些线性误差。没有数据,很难判断,但这是我对您的问题的再现:
matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
x = np.random.lognormal(5, 1, 10000)
y = x * np.random.normal(5,1,10000)
f, axes = plt.subplots(2, 1, figsize=(16,12))
sns.scatterplot(x,y, ax=axes[0])
sns.distplot(np.log(y), ax=axes[1])
Scatterplot of x and y, distribution of log(y)
然后我们可以对 x 系数和相关 y 误差建模:
with pm.Model() as model:
sigma = pm.InverseGamma('sigma', mu=(y/x).std(), sd = (y/x).std()/len(x))
#intercept = pm.Normal('Intercept', 0, sigma=1)
x_coeff = pm.Normal('x_coeff', (y/x).mean(), sigma=1)
l = pm.Normal('l', mu=x_coeff, sigma=sigma, observed=y/x)
trace = pm.sample(3000, tune=1000, cores=4)
现在绘制我们得到的线:
f, axes = plt.subplots(figsize=(16,8))
sns.scatterplot(x, y, ax=axes)
for (_,val) in pm.stats.quantiles(trace['x_coeff']).items():
plt.plot(x, val*x, color='b')
for (__, sd) in pm.stats.quantiles(trace['sigma']).items():
plt.plot(x, (val+2*sd)*x, color='r')
plt.plot(x, (val-2*sd)*x, color='r')
x coefficients plotted with 2*sd positive and negative