ALPS の pyalps.checkSteadyState() についての疑問
間違いがありましたらコメントにてご指摘下さい。
pyalps.checkSteadyState() とは
ALPS には pyalps.checkSteadyState() なる関数がある。
系が平衡状態にあるかを z 検定をしてチェックする*1もので、原理などは Monte_Carlo_Equilibration - ALPS project に書いてある。
仕様としては
pyalps.checkSteadyState(sets=None, outfile=None, observable=None, confidenceInterval=0.6827, simplified=False, includeLog=False)
とのこと。
で、このALPS wiki に書いてることとソースの内容が一致しないように感じた。
ALPS wiki に書いてあること
Monte_Carlo_Equilibration - ALPS project によると次の手順を踏んでいる。
今後のため少しノーテーションを変えています。
- 回の MCSで得られた物理量 の timeseries を とする。
- 関数 を用意して、最小二乗法によりデータ点 を によって fitting を行う。
- 最小二乗法により、傾きの値 と分散値 *2が得られる。
- この得られた傾きの値 がゼロであれば一定値をとっているので平衡状態と考えられる。
実際は統計的に一定値になることはまずないので以下の仮説のもと検定を行う。
(標本の数は十分あるので標本平均の分散から逆算により母分散もわかっているとする。)
- 帰無仮説 :
- 対立仮説 :
有意水準を とすると信頼係数 は 。*3
scipy の ppf 関数(パーセントポイント関数)を用いると棄却水準の境目となる は z0 = scipy.stats.norm.ppf(1-0.5*alpha) = scipy.stats.norm.ppf(0.5+0.5*gamma) となる。
*4
と標準化(今回は対称性から絶対値をつける)しておくとこれが棄却域に入ることは z > z0 と同値、つまり z > z0 であれば有意水準 のもとで仮設 は棄却される。
ここで重要なのは棄却されなかった場合に仮設 があっているかは完全に保証できないことだ。
つまり、ALPS wiki による pyalps.checkSteadyState() の原理では「収束しているかどうか」の判定に使うのではなく「収束しているかどうかの必要条件」のチェックとして使うものである。
ソースの内容
とまあここまでであれば非常にわかりやすい。
しかしソースを見たらさっきの ALPS wiki 通りじゃなくて非常に悩んだ。
pyalps.checkSteadyState() は Download したときの alps-2.2.b3-r7462-srcalps/lib/pyalps/tools.py に定義されている。
実質的に計算しているのは次の通り。
################################## # # File path : alps-2.2.b3-r7462-srcalps/lib/pyalps/tools.py # line : 535-547 # see also : http://alps.comp-phys.org/ # Copyright (C) 2010 by Bela Bauer <bauerb@phys.ethz.ch> # ################################## ts = pyalps.loadTimeSeries(outfile, observable); ### y N = ts.size; idx = scipy.linspace(1, N, N); ### x beta1 = scipy.polyfit(idx, ts, 1)[0]; ### slope ts_std = np.std(ts, ddof=1); ### unbiased estimate of standard deviation in y beta1_std = math.sqrt((12.*ts_std*ts_std)/(N * (N*N-1))); ### unbiased estimate of standard deviation in slope z = abs(beta1/beta1_std); z0 = scipy.stats.norm.ppf((1.-confidenceInterval) + 0.5*(confidenceInterval)); result = z < z0;
一番のネックは z0 の定義部分。ここは z0 = scipy.stats.norm.ppf(1-0.5*gamma) となっている。
さっきの原理と違うじゃん…。
このソースが正しいとなると次のことをやっている。
仮説として
- 帰無仮説 :
- 対立仮説 :
とおく。
その時の棄却域の境界は の信頼度を としているので帰無仮説の信頼係数としては を採用すればいい。
つまり、有意水準は でありソースの z0 は正しくなる。
棄却域(通常は裾野だが今回は中心部分)に入ることは z < z0 であると同値、つまり帰無仮説 が棄却され、対立仮説 を得ることが出来る。
…なんかこれ超胡散臭くないですか?こういう検定ってやっていいの?
これが「正しい検定」であれば素晴らしいと思うんですよ、 であるかがスパッとわかるから。
ただちょっとこれはアカンのでは?と私は思います。
自分の中の結論
ここに書いてあるのはあくまで上記の内容を踏まえた私の考えです。
ALPS wiki 通りのスクリプト
pyalps は弄りたくなかったので ALPS wiki 通りのスクリプト書いた。
すでに述べたように T_or_F_wiki の値は「収束しているかどうか」の判定に使うのではなく「収束しているかどうかの必要条件」のチェックとして使うもの なのでご注意を。
一応、pyalps.checkSteadyState() の方で出る z0 も出力してます。
*1:通常、収束度を調べる場合は物理量の時間プロットや binning 解析、物理量に MCS 依存性があるかなどを用いるのが普通だと認識してる。これを見つけた時はえらい便利なものがあるなという印象だった。
*2:ソースでは不偏標準偏差 (unbiased standard deviation) を としている。
*3:Monte_Carlo_Equilibration - ALPS project では信頼係数を とおいているが普通、有意水準を とおくのでその慣習に則っている。ALPS wiki での はここでいうところの です。
*4:これは Monte_Carlo_Equilibration - ALPS project における と一致しない。ただ、scipy.stats.norm.ppf(0.5+0.5*gamma) は scipy.stats.norm.ppf(0.5-0.5*gamma) の絶対値と同じなので と修正すれば大丈夫だろう。