web-dev-qa-db-ja.com

sklearn.datasetsを使用したPyMC3ベイズ線形回帰予測

_PyMC3_とREAL DATAを使用して、ベイジアン線形回帰モデルを実装しようとしています。 (つまり、線形関数+ガウスノイズからではありません)_sklearn.datasets_のデータセットから。形状が_(442, 10)_である属性の数が最も少ない回帰データセット(つまり、load_diabetes())を選択しました。つまり、_442 samples_および_10 attributes_です。

私はモデルが機能していると信じています。事後確率は、このようなものがどのように機能するかを理解するために試して予測するのに十分まともなように見えますが...これらのベイジアンモデルで予測する方法がわからないことに気付きました! glmおよびpatsy表記を使用するときに実際に何が起こっているのかを理解するのが難しいため、この表記の使用を避けようとしています。

私は次のことを試みました: pymc3の推定パラメーターから予測を生成する そして http://pymc-devs.github.io/pymc3/posterior_predictive/ しかし、私のモデルは非常にひどいです予測するか、私はそれを間違っています。

私が実際に予測を正しく行っている場合(おそらくそうではありません)、誰かが私のモデルを最適化するのを手伝ってくれますか?少なくとも_mean squared error_、_absolute error_、またはそのようなものがベイジアンフレームワークで機能するかどうかはわかりません。理想的には、number_of_rows = _X_te_属性/データテストセットの行数、および事後分布からのサンプルとなる列の数の配列を取得したいと思います。

_import pymc3 as pm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
from scipy import stats, optimize
from sklearn.datasets import load_diabetes
from sklearn.cross_validation import train_test_split
from theano import shared

np.random.seed(9)

%matplotlib inline

#Load the Data
diabetes_data = load_diabetes()
X, y_ = diabetes_data.data, diabetes_data.target

#Split Data
X_tr, X_te, y_tr, y_te = train_test_split(X,y_,test_size=0.25, random_state=0)

#Shapes
X.shape, y_.shape, X_tr.shape, X_te.shape
#((442, 10), (442,), (331, 10), (111, 10))

#Preprocess data for Modeling
shA_X = shared(X_tr)

#Generate Model
linear_model = pm.Model()

with linear_model: 
    # Priors for unknown model parameters    
    alpha = pm.Normal("alpha", mu=0,sd=10)
    betas = pm.Normal("betas", mu=0,#X_tr.mean(), 
                               sd=10, 
                               shape=X.shape[1])
    sigma = pm.HalfNormal("sigma", sd=1)

    # Expected value of outcome
    mu = alpha + np.array([betas[j]*shA_X[:,j] for j in range(X.shape[1])]).sum()

    # Likelihood (sampling distribution of observations)
    likelihood = pm.Normal("likelihood", mu=mu, sd=sigma, observed=y_tr)

    # Obtain starting values via Maximum A Posteriori Estimate
    map_estimate = pm.find_MAP(model=linear_model, fmin=optimize.fmin_powell)

    # Instantiate Sampler
    step = pm.NUTS(scaling=map_estimate)

    # MCMC
    trace = pm.sample(1000, step, start=map_estimate, progressbar=True, njobs=1)


#Traceplot
pm.traceplot(trace)
_

enter image description here

_# Prediction
shA_X.set_value(X_te)
ppc = pm.sample_ppc(trace, model=linear_model, samples=1000)

#What's the shape of this? 
list(ppc.items())[0][1].shape #(1000, 111) it looks like 1000 posterior samples for the 111 test samples (X_te) I gave it

#Looks like I need to transpose it to get `X_te` samples on rows and posterior distribution samples on cols

for idx in [0,1,2,3,4,5]:
    predicted_yi = list(ppc.items())[0][1].T[idx].mean()
    actual_yi = y_te[idx]
    print(predicted_yi, actual_yi)
# 158.646772735 321.0
# 160.054730647 215.0
# 149.457889418 127.0
# 139.875149489 64.0
# 146.75090354 175.0
# 156.124314452 275.0 
_
18
O.rka

モデルの問題の1つは、データのスケールが大きく異なることだと思います。「X」の範囲は最大0.3、「Y」の範囲は最大300です。したがって、事前確率で指定されているより大きな勾配(およびシグマ)を期待する必要があります。論理的なオプションの1つは、次の例のように事前確率を調整することです。

_#Generate Model
linear_model = pm.Model()

with linear_model: 
    # Priors for unknown model parameters    
    alpha = pm.Normal("alpha", mu=y_tr.mean(),sd=10)
    betas = pm.Normal("betas", mu=0, sd=1000, shape=X.shape[1])
    sigma = pm.HalfNormal("sigma", sd=100) # you could also try with a HalfCauchy that has longer/fatter tails
    mu = alpha + pm.dot(betas, X_tr.T)
    likelihood = pm.Normal("likelihood", mu=mu, sd=sigma, observed=y_tr)
    step = pm.NUTS()
    trace = pm.sample(1000, step)

chain = trace[100:]
pm.traceplot(chain);
_

enter image description here

事後予測チェックは、多かれ少なかれ合理的なモデルがあることを示します。

_sns.kdeplot(y_tr, alpha=0.5, lw=4, c='b')
for i in range(100):
    sns.kdeplot(ppc['likelihood'][i], alpha=0.1, c='g')
_

enter image description here

もう1つのオプションは、データを標準化して同じスケールに配置することです。そうすることで、勾配が+ -1前後になり、一般に、任意のデータに同じ拡散事前分布を使用できます(情報がない限り便利です)。使用できる事前確率)。実際、多くの人が一般化線形モデルにこの方法を推奨しています。これについては、本で詳しく読むことができます ベイジアンデータ分析を行う または 統計的再考

値を予測したい場合は、いくつかのオプションがあります。1つは、次のような推定パラメーターの平均を使用することです。

_alpha_pred = chain['alpha'].mean()
betas_pred = chain['betas'].mean(axis=0)

y_pred = alpha_pred + np.dot(betas_pred, X_tr.T)
_

もう1つのオプションは、_pm.sample_ppc_を使用して、推定の不確実性を考慮した予測値のサンプルを取得することです。

PPCを実行する主なアイデアは、予測値をデータと比較して、両方が一致する場所と一致しない場所を確認することです。この情報は、たとえばモデルを改善するために使用できます。

pm.sample_ppc(trace, model=linear_model, samples=100)

それぞれが331個の予測観測値を持つ100個のサンプルを提供します(この例では、_y_tr_の長さは331であるため)。したがって、予測された各データポイントを、後方から取得したサイズ100のサンプルと比較できます。事後分布自体が可能なパラメーターの分布であるため、予測値の分布が得られます(分布は不確実性を反映しています)。 _sample_ppc_の引数に関して:samplesは、後方から取得するポイントの数を指定します。各ポイントはパラメーターのベクトルです。 sizeは、パラメーターのベクトルを使用して予測値をサンプリングする回数を指定します(デフォルトでは_size=1_)。

この中で_sample_ppc_を使用する他の例があります チュートリアル

15
aloctavodia

(X --u)/σを標準化すると、ベータの分散はすべての変数で均一ですが、スケールが異なるため、独立変数もうまく機能する可能性があります。

もう1つのポイントは、pm.math.dotを使用する場合、f(x) =切片+Xβ+εであるとすると、行列ベクトル積を計算する方が効率的かもしれません。

2
minggli