繰り返し1要因分散分析(固定効果)
2026.07改訂
分散分析は、分散(平方和)の分割に基づく分析法であるが、目的は分散の分割に基づいて要因の効果の有無を調べることである。要因の効果は、要因の各水準の値が示されると分かり易い。各水準と従属変数の関係を確率モデルで表して、水準の値の事後分布を求めてみた。
ケース
の水準
における値が次の確率分布に従うとする。
![]()
ケースパラメータが
であり、水準パラメータが
である。
の事前分布を平均値0の正規分布として原点を設定する。
このモデルに対するStanスクリプトをリスト1のように用意した。ファイルは、filesOneFctrFixedRep.zipにまとめた。
リスト1 1要因分散分析のStanスクリプト(OneFctrFixedRep.stan)
data {
int J;
int N;
array[N, J] real X;
real sd_subj;
real sd_f;
real mean_f;
}
parameters {
array[N] real mu;
array[J] real f;
real<lower=0.0001>
sgm;
}
model {
sgm - 0.0001 ~ uniform(0,
1000);
for (j in 1:J) {
f[j]
~ normal(mean_f, sd_f);
}
for (i in 1:N) {
mu[i] ~ normal(0,
sd_subj);
for
(j in 1:J) {
X[i][j] ~ normal(mu[i] + f[j], sgm) ;
}
}
}
リスト1のStanスクリプトを用いてベイズ分析を行うPythonスクリプトをリスト2のように作成した。
リスト2用の入力データのサンプルを図1のように用意した。

図1
図1の形式に従うものであれば他のものでもよい。1行目に水準名、1列目にケース名を置き、水準名とケース名の交点のセルに該当するデータを書く。
リスト1とリスト2のスクリプトファイルと図1のデータファイル(他のExcelファイルでもよい)を同じフォルダに置く。そのフォルダにカレントディレクトリを移して、次のpythonコマンドを実行するとファイル名の設定が求められる。
(stan) ****/filesOneFctrFixedRep$
python OneFctrFixedRep.py
入力データファイル(*.xlsx)= datarep.xlsx
出力ファイル(*.txt)= results.txt
画像保存ファイル(*.png)= Fig.png
上の例では、入力データファイル名は図1のファイル名が設定されている。出力ファイル名と画像保存ファイル名は、ファイル拡張子がそれぞれ「*.txt」、「*.png」の任意のファイル名である。
ファイル名の設定が終わると、ファイルが読み込まれ、Stanスクリプトがコンパイルされる。コンパイル後、MCMCサンプリングが始まり、終了後、トレース図が表示される(図2)。

図2
図2のWindowを閉じると、図3のグラフが表示される。

図3
水準の効果
(グラフでは
となっている)の事後分布のグラフである。水準1(a1)と水準4(a4)が事後分布が重なっており、水準3(a3)の事後分布はそれらより左側、水準2(a2)のグラフはそれらより右側に位置している。すなわち、水準のパラメータ値は、水準3<(水準1、水準4)<水準2の関係にあることが分かる。
図3のWindowを閉じると、スクリプトの実行終了である。
なお、現在(2026.07.09)matplotlib 3.11で実行するとエラーが出る。matplotlib 3.10に換えると大丈夫である。matplotlib 3.10への交換は、次のコマンド
conda install
matplotlib=3.10
でできた。
Gelman, A., Hill, J., & Vehtari, A. (2021). Regression and other stories. Cambridge University
Kirk, R.E. (1995). Experimental design: Procedures for the behavioral sciences, third ed. Brooks/Cole Publishing Company.
Winer, B. J., Brown, D.R., & Michels, K.M. (1991). Statistical principles in experimental design, third ed. McGraw-Hill, Inc.
リスト2 繰り返し1要因固定効果モデルのPythonスクリプト例(OneFctrFixedRep.py)
import numpy as np
import scipy.stats as ss
import scipy.optimize as so
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
from cmdstanpy import CmdStanModel
import seaborn as sb
import arviz as az
finnm = input('入力データファイル(*.xlsx)= ')
txtoutnm = input('出力ファイル(*.txt)= ')
foutnm = input('画像保存ファイル(*.png)= ')
txtout = open(txtoutnm, 'w')
#
# Excelファイルの読み込み
# モジュール xlrd がインストール済みであること
#
xlsx_fl = pd.ExcelFile(finnm)
# ExcelファイルからExcelFile型オブジェクトを生成
data_xlsx =
pd.read_excel(xlsx_fl, header =
None) # ExcelFile型オブジェクトからDataFrame型オブジェクトを生成
data = data_xlsx.values
# Dataframe型オブジェクトからnumpyの配列オブジェクトを生成
print('\n', data)
txtout.write('\n入力データファイル: {}\n'.format(finnm))
A_name = data[0, 1:]
a = len(A_name)
N = len(data) - 1
X = np.array(data[1:,1:],
dtype=float)
print('A = ', A_name)
print('a = ', a)
print('N = ', N)
txtout.write('\nA =
{}\n'.format(A_name))
txtout.write('a = {}\n'.format(a))
txtout.write('N = {}\n'.format(N))
print(X)
txtout.write('\n{}\n'.format(X))
min_X = np.min(X)
max_X = np.max(X)
sd_subj = np.mean(np.std(X, axis=0))
print('sd_subj =', sd_subj)
mean_f = np.mean(X)
print('mean_f =', mean_f)
sd_f = np.mean(np.std(X, axis=1))
print('np.sd =', np.std(X, axis=1))
print('sd_f =', sd_f)
StanData = {'J': a, 'N': N, 'X': X,
'sd_subj':sd_subj, 'sd_f':sd_f, 'mean_f':mean_f}
print('a,N', a, N,'\nX =\n', X)
model =
CmdStanModel(stan_file='OneFctrFixedRep.stan')
fit = model.sample(data=StanData)
print(fit.diagnose())
print(fit.summary())
txtout.write(f'{fit.summary()}')
infdata = az.from_cmdstanpy(fit) # Arviz InfereceData型へ変換
az.plot_trace_dist(infdata)
plt.tight_layout()
plt.savefig(foutnm[:-4] +
'_trace.png')
savedFiles = [foutnm[:-4] +
'_trace.png']
plt.show()
fit = fit.draws_pd()
# Pandas DataFrame型への変換
print(fit.keys())
for j in range(a):
sb.kdeplot(fit[f"f[{j+1}]"], label=f"a{j+1}")
plt.xlabel('a', fontsize=16)
plt.legend(fontsize=14)
plt.savefig(foutnm[:-4] + '_a.png')
savedFiles += [foutnm[:-4] + '_a.png']
plt.show()
txtout.close()
savedFiles.append(txtoutnm)
print('\n保存ファイル:')
for nm in savedFiles:
print(' ', nm)
print()