Up

PyStan 3 試用記

2022.10, 2024.09

 

WinodwsUbuntuCentOS Stream 9PyStan 3を使ってみた(2024.09)。Windowsは、WindowsにインストールされたUbuntu22(以下、Ubuntu22/Windowsと略記)での使用である。WindowsへのUbuntuのインストールは、このウェブサイトなどを参照されたい。PCに直接インストールされたUbuntu22(以下、Ubuntu22/PCと略記)でのPyStan3の使用は、CentOS Stream 9の場合と同様であった。

 

Ubuntu 22をインストールするときは、PowerShellにおいてコマンド

 

wsl.exe --install Ubuntu-22.04

 

を実行すればよい。

 

Ubuntu22/WindowsにおいてPyStan 3が使い難くなっていた。しばらくすれば、Ubuntu22/Windowsにおいても、CentOS Stream 9の場合と同様に使い易くなると思われるが、まず、CentOS Stream 9での使用を報告し、その後、Ubuntu22/Windowsの場合について説明する。いずれの場合も、Anacondaをインストールして、Python 3.12の仮想環境を用意し、PyStan 3をコマンド

 

pip install pystan

 

でインストールした。Pythonのスクリプト内でPyStan 3importするときは

 

import stan

 

である。

 

PyStan 3をインストールするとき、あるいはPyStan 3実行するとき、インストールできない、あるいは実行できないときは、C++コンパイラがインストールされていない可能性がある。コマンド「g++」を実行してみて、「g++」が見つかりません、コマンド「*****」でインストールして下さいというようなメッセージが表示されたら、その通り実行してみる。

g++」のインストールが済めば、PyStan 3のインストールができて、PyStan 3スクリプトの実行ができるはずである。

 

まず、CentOS Stream 9およびUbuntu22/PCでの利用について説明する。Ubuntu22/Windowsの場合については、このウェブページの後半で説明する。

スクリプトファイルは、まとめて圧縮ファイルsample_script.zipとした。

PyStanについては、<岡本安晴「いまさら聞けないPythonでデータ分析」丸善出版>で説明している。

 

 

 

CentOS Stream 9およびPCに直接インストールされたUbuntu22/PCの場合

 

 

CentOS Stream 9の場合も、Ubuntu22/PCの場合も同じであるので、CentOS Stream 9の場合について説明する。Anacondaをインストールして、AnacondaPython仮想環境においてPyStan 3を利用する。Anacondaのインストールについては、別のウェブサイトで説明している。

Anacondaのインストールの最後において、初期化を行うかどうか聞いてくるが、「yes」と答えておくと楽である。インストール後、日本語入力などで問題が生じたときは、コマンド「conda config set auto_activate_base false」を実行すればよい。実行後、再起動すれば、端末の起動時に自動的に仮想環境がアクティブになっているということは無くなるが、コマンド「conda activate」を実行すればアクティブになる。

 

実行環境は、CentOS Stream 9 にインストールしたAnacondaの仮想環境としてPython 3.12の仮想環境を用意した。PyStan 3は、用意した仮想環境においてコマンド

 

pip install pystan

 

によりインストールした。

必要に応じてライブラリをインストールするが、scipyはバージョン1.12のものをコマンド

 

conda install scipy=1.12

 

でインストールする。すでに他のバージョンのものがインストールされているときは、それと置き換えられる。

 

以下、2項分布単回帰モデル2変量正規分布について説明する。

 

 

 

2項分布

 

 

リスト1にスクリプト例を示す。

リスト1のスクリプトを実行すると、FigKDE.pngが表示される。

FigKDE.png

 

これは、スクリプト

 

sb.kdeplot(p_smpls[0])

 

により表示されるものである。

FigKDE.pngの表示されているWindowを閉じると、FigPD.pngが表示される。

FigPD.png

 

これは、コード

 

sb.kdeplot(df['p'])

 

により表示されるものである。いずれも、pの事後分布で、同じものである。

FigPD.pngWindowを閉じると、図FigTrace.pngが表示される。

FigTrace.png

 

FigTrace.pngWindowを閉じると、スクリプトの実行終了である。

 

 

 

リスト1 2項分布の例

 

import stan

import matplotlib.pyplot as plt

import seaborn as sb

import arviz as az

 

binomial_model = """

    data {

        int N;

        int k;

    }

    parameters {

        real<lower = 0.0, upper = 1.0> p;

    }

    model {

        k ~ binomial(N, p);

    }

"""

 

binomial_data = {'N':10, 'k':7}

 

sm = stan.build(binomial_model, data = binomial_data)

fit = sm.sample()

 

print('fit =\n', fit, '\n')

 

p_smpls = fit['p']

print('p_smpls =\n', p_smpls)

 

sb.kdeplot(p_smpls[0])

plt.savefig('FigKDE.png')

plt.show()

plt.close()

 

df = fit.to_frame()

sb.kdeplot(df['p'])

plt.savefig('FigPD.png')

plt.show()

plt.close()

 

inference_data = az.from_pystan(posterior = fit, posterior_model = sm)

az.plot_trace(inference_data)

plt.savefig('FigTrace.png')

plt.show()

plt.close()

 

 

 

 

単回帰モデル

 

単回帰モデルの例として、リスト2を用意した。

リスト2を実行すると、下図の散布図FigXY.pngが表示される。

FigXY.png

 

これは、次のスクリプトにより作成されたデータXsYsの散布図である。

 

Xs = ss.uniform.rvs(loc = 10, scale = 20, size = 100)

Es = ss.norm.rvs(loc = 0, scale = 1, size = 100)

Ys = 10 + 0.5 * Xs + Es

 

plt.scatter(Xs, Ys)

 

このデータに、次の単回帰モデルを当てはめている。

 

        Y ~ normal(a + b*X, sgm);

 

FigXY.pngWindowを閉じると、トレース図FigTrace.pngが表示される。

FigTrace.png

 

トレース図FigTrace.pngWindowを閉じると、係数abの事後分布の散布図Fig_ab.pngが表示される。

Fig_ab.png

 

独立変数の中心化(centering)を行っていないので、強い相関が認められる。

 

 

 

リスト2 単回帰モデルの例

 

import stan

import scipy.stats as ss

import matplotlib.pyplot as plt

import seaborn as sb

import arviz as az

 

Xs = ss.uniform.rvs(loc = 10, scale = 20, size = 100)

Es = ss.norm.rvs(loc = 0, scale = 1, size = 100)

Ys = 10 + 0.5 * Xs + Es

 

plt.scatter(Xs, Ys)

plt.savefig('FigXY.png')

plt.show()

plt.close()

 

simple_reg_model = """

    data {

        int N;

        vector[N] X;

        vector[N] Y;

    }

    parameters {

        real a;

        real b;

        real<lower = 0> sgm;

    }

    model {

        a ~ normal(0, 10);

        b ~ normal(0, 10);

        sgm ~ exponential(0.1);

        Y ~ normal(a + b*X, sgm);

    }

"""

 

simple_reg_data = {'N':len(Xs), 'X':Xs, 'Y':Ys}

 

sm = stan.build(simple_reg_model, data = simple_reg_data)

fit = sm.sample()

 

print('fit =\n', fit, '\n')

 

infer_data = az.from_pystan(posterior=fit, posterior_model=sm)

smry = az.summary(infer_data)

print(smry)

 

az.plot_trace(infer_data)

plt.savefig('FigTrace.png')

print('FigTrace.png was saved.')

plt.show()

plt.close()

 

a_smpls = fit['a']

b_smpls = fit['b']

plt.scatter(a_smpls, b_smpls)

plt.xlabel('a')

plt.ylabel('b')

plt.savefig('Fig_ab.png')

plt.show()

plt.close()

 

 

 

 

2変量正規分布

 

 

2変量正規分布を用いたスクリプト例をリスト3のように用意した。

リスト3を実行すると、下図の散布図FigXY.pngが表示される。

FigXY.png

 

これは、次のコードで生成されたデータの散布図である。

 

X = ss.multivariate_normal.rvs([0,0],[[1, 0.8],[0.8,1]], size = 100)

 

このデータに対して、次の多変量正規分布のモデルを適用している。

 

        X ~ multi_normal(mu, cov);

 

散布図FigXY.pngWindowを閉じると、トレース図FigTrace.pngが表示される。

FigTrace.png

 

トレース図FigTrace.pngWindowを閉じると、相関係数rhoの事後分布が表示される。

FigRho.png

 

事後分布のグラフFigRho.pngWindowを閉じると、スクリプトの実行終了である。

 

 

 

リスト3 2変量正規分の例

 

import stan

import scipy.stats as ss

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sb

import arviz as az

 

X = ss.multivariate_normal.rvs([0,0],[[1, 0.8],[0.8,1]], size = 100)

print(X)

plt.scatter(X.T[0], X.T[1])

plt.savefig('FigXY.png')

plt.show()

plt.close()

 

binormal_model = """

    data {

        int N;

        array[N] vector[2] X;

    }

    parameters {

        vector[2] mu;

        vector<lower=0.0>[2] v_sgm;

        real<lower = -1, upper = 1> rho;

    }

    transformed parameters {

        cov_matrix[2] cov;

        vector[2] sgm;

        sgm[1] = 0.001 + v_sgm[1];

        sgm[2] = 0.001 + v_sgm[2];

        cov[1][1] = sgm[1]*sgm[1];

        cov[1][2] = rho*sgm[1]*sgm[2];

        cov[2][1] = rho*sgm[1]*sgm[2];

        cov[2][2] = sgm[2]*sgm[2];

    }

    model {

        mu ~ normal(0, 10);

        v_sgm ~ exponential(0.1);

        rho ~ uniform(-1,1);

        X ~ multi_normal(mu, cov);

    }

"""

X = np.array(X)

print(len(X))

binormal_data = {'N':len(X), 'X':X}

 

sm = stan.build(binormal_model, data = binormal_data)

fit = sm.sample()

 

print('fit =\n', fit, '\n')

 

inference_data = az.from_pystan(posterior = fit, posterior_model = sm)

smry = az.summary(inference_data)

print('Summary =\n',smry)

 

#plt.figure(figsize=(10,7))

az.plot_trace(inference_data, figsize=(10,6))

plt.tight_layout()

plt.savefig('FigTrace.png')

print('FigTrace.png was saved.')

plt.show()

plt.close()

 

mu_smpls = fit['mu']

print('mu_smpls =\n', mu_smpls)

 

df = fit.to_frame()

print('df =\n', df, '\n\n')

for v in zip(df['mu.1'][:5], df['mu.2'][:5], df['cov.2.2'][:5]):

    print(v)

   

sb.kdeplot(df['rho'])

plt.savefig('FigRho.png')

plt.show()

plt.close()

 

 

 

 

WindowsにインストールされたUbuntu22/Windowsの場合におけるPyStan 3の利用

 

 

WindowsにインストールされたUbuntu22/Windowsの場合は、StanによるMCMCサンプリングのみをUbuntu22/Windowsで行い、MCMCサンプルをファイルに保存して、Windowsにおいて保存したMCMCサンプルを読み出して分析する。

UbuntuWindowsWSLにインストールしたUbuntu 22を利用した。Ubuntu 22/Windowsにおいて、上のCentOS Stream 9と同様の手続きで、Python 3.12の仮想環境をAnaconda/Ubuntu22/WSL/Windowsに用意してPyStan 3をインストールした。Scipyはバージョン1.12scipy1.12をインストールした。

 

以上の環境の下で、2項分布のMCMCサンプリングを行うリストU1Python3.12/Anaconda/Ubuntu22/WSL/Windowsにおいて実行した。

 

 

リストU1  2項分布のMCMCサンプリング

 

import stan

import arviz as az

import pickle

 

binomial_model = """

    data {

        int N;

        int k;

    }

    parameters {

        real<lower = 0.0, upper = 1.0> p;

    }

    model {

        k ~ binomial(N, p);

    }

"""

 

binomial_data = {'N':10, 'k':7}

 

sm = stan.build(binomial_model, data = binomial_data)

fit = sm.sample()

 

df = fit.to_frame()

with open('df.pkl', 'wb') as f:

    pickle.dump(df, f)            #   DataFrame型を保存

 

inference_data = az.from_pystan(posterior = fit, posterior_model = sm)

with open('inf_d.pkl', 'wb') as f:

    pickle.dump(inference_data, f)   #   InferenceData型を保存

smry = az.summary(inference_data)

print('Summary =\n',smry)            #   MCMCサンプリングの統計量の出力

 

 

MCMCサンプルは次のコードで、DataFrame型のものとInferenceData型のものの2つを保存している。

 

df = fit.to_frame()

with open('df.pkl', 'wb') as f:

    pickle.dump(df, f)            #   DataFrame型を保存

 

inference_data = az.from_pystan(posterior = fit, posterior_model = sm)

with open('inf_d.pkl', 'wb') as f:

    pickle.dump(inference_data, f)   #   InferenceData型を保存

 

 

上の保存されたデータdf.pklinf_d.pklを、Windows上において読み込み、処理を行うスクリプトを、リストUのように用意した。

 

 

リストU2  MCMCサンプルのファイルを読み込み処理するスクリプト

 

import matplotlib.pyplot as plt

import seaborn as sb

import arviz as az

import pickle

 

with open('df.pkl', 'rb') as f:

    df = pickle.load(f)

 

 

sb.kdeplot(df['p'])

plt.savefig('FigPD.png')

plt.show()

plt.close()

 

with open('inf_d.pkl', 'rb') as f:

    inference_data = pickle.load(f)

 

az.plot_trace(inference_data)

plt.savefig('FigTrace.png')

plt.show()

plt.close()

 

print(az.summary(inference_data))

 

 

 

リストU2のスクリプトを、リストU1で保存されたファイルの置かれているフォルダで実行すると、まず、pの事後分布のグラフ図U1が表示される。

U1

 

図U1のWindowを閉じると、トレース図(図U2)が表示される。

U2

 

U2Windowsを閉じると、スクリプトの実行は終了して、端末には次の出力が表示されている。

 

    mean     sd  hdi_3%  hdi_97%  mcse_mean  mcse_sd  ess_bulk  ess_tail  r_hat

p  0.666  0.135   0.394    0.884      0.004    0.003    1298.0    1717.0    1.0

 

これは、次のコード

 

print(az.summary(inference_data))

 

によるものである。

 

 

 

Up