Up

カイ2乗分布の計算

 

 自由度dのカイ2乗分布(-distribution

に従う確率変数Xに対して

の関係にあるあるいはpを一方が与えられたとき他方を求めるプログラムcalc_chi2.exeを作成した。実行形式のプログラムcalc_chi2.exeは、.NET Framework3.5がインストールされているパソコンであれば、ファイル名calc_chi2.exeをクリックすることにより、ダウンロード、実行できる。プログラムのソースファイルなどをまとめたものは、圧縮ファイルcalc_chi2.zipとして用意したので、ファイル名calc_chi2.zipをマウスの右ボタンでクリックしてダウンロードできる。ダウンロードしたファイルはマウスの右ボタンで表示されるメニュから「解凍」あるいは「展開」を選んで解凍すれば、Visual C++などで開くことができる。なお、上の式ではガンマ関数を求めることになるが、ガンマ関数を求めずに計算するプログラムも<ガンマ関数の計算を行わない方法>に用意した。

 プログラムは、実行すると図1のウィンドウ・フォームが表示される。

図1 実行開始時のウィンドウ・フォーム

 

自由度dfの値をそれぞれの右側のテキストボックスに設定して「chi2 -> p」ボタンをクリックすると、「p =」の右側のテキスト・ボックスに対応するpの値が表示される(図2)

図2 計算結果の表示。

 

p =」の右側に値を設定して「p -> xhi2」ボタンをクリックすると対応するの値が「Chi-Square =」の右側のテキスト・ボックスに表示される(図3)。

図3

 

累積確率は適応的数値積分によって求めているが、詳しくは

岡本安晴「統計学を学ぶための数学入門[]」、2009、培風館8.6節「積分の数値計算――ガウス・ルジャンドルの積分公式と適応的方法――」

などを参照されたい。

 

ガンマ関数の計算を行わない方法

 カイ2乗分布の式

により計算するプログラムを作成した。実行形式プログラムcalc_chi2a.exeは、Visual Studio 2013のインストールされているPCであれば、ファイル名calc_chi2a.exeをクリックして、ダウンロード・実行することがきる。プログラムのソースコードファイルなどをまとめた圧縮ファイルcalc_chi2a.zipも用意した。圧縮ファイル名calc_chi2a.zipをクリックしてダウンロード・解凍(展開)すればVisual Studio 2013で開くことができる。

 なお、カイ2乗分布の分布関数は自由度をパラメータとしてもつので、分布関数を関数オブジェクトとして表し、自由度をそのメンバーとして設定し、積分などは関数テンプレートとして作成した。ソースコードは以下のようである。

 

//

//                      Yasuharu Okamoto, 2015.12

//

#ifndef CHISQRDISTRI_CK

#define CHISQRDISTRI_OK

 

#include "adapIntgrtn.h"

 

using namespace adapInt;

 

namespace ChiSqrD {

 

        inline double sqr(double v){

                return v * v;

        }

 

        class Chi0 {

        public:

                double df;

                Chi0(){}

                Chi0(double vdf){

                        df = vdf;

                }

                double operator()(double chi){

                        double v = ((df / 2.0) - 1.0) * Math::Log(chi) - (chi / 2.0);

                        return Math::Exp(v);

                }

        };

 

        class Chi0t{

        public:

                double df;

                Chi0 chi0;

                Chi0t(){}

                Chi0t(double vdf){

                        df = vdf;

                        chi0.df = df;

                }

                double operator()(double t){

                        double v = chi0(Math::Tan(t)) / sqr(Math::Cos(t));

                        return v;

                }

        };

 

        class CumChi2 {

        public:

                double df;

                Chi0 chi0;

                double coeff;

                CumChi2(){}

                CumChi2(double vdf){

                        df = vdf;

                        chi0.df = df;

                        Chi0t chi0t(df);

                        TAdaptiveGL<Chi0t> gl(chi0t);

                        double IntgrlChi0 = gl.integral(0.0, Math::PI / 2.0);

                        coeff = 1.0 / IntgrlChi0;

                }

                void setCumChi2(double vdf){

                        df = vdf;

                        chi0.df = df;

                        Chi0t chi0t(df);

                        TAdaptiveGL<Chi0t> gl(chi0t);

                        double IntgrlChi0 = gl.integral(0.0, Math::PI / 2.0);

                        coeff = 1.0 / IntgrlChi0;

                }

                double operator()(double chi2){

                        if (df < 1.0) throw gcnew Exception("df = " + df.ToString() + " < 1.0");

                        TAdaptiveGL<Chi0> gl(chi0);

                        double v = gl.integral(0.0, chi2);

                        return v * coeff;

                }

        };

 

        //     Bisection法による根の計算   

        template<class TF>

        void TBisection(TF & f,

                double s,                                       //   fが増加関数のとき s > 0.0

                double c,                                       //   根に対する関数値

                double L_b, double U_b,         //   根の存在区間の下限と上限

                double & Root,                          //     f(Root) = c

                double acc){

                if ((f(L_b) - c) * (f(U_b) - c) > 0.0){

                        throw  gcnew Exception("上限と下限の組み合わせが不適切です。");

                }

                do {

                        double m = 0.5 * (L_b + U_b);

                        double v = f(m);

                        if (s * (v - c) > 0.0) {

                                U_b = m;

                        }

                        else {

                                L_b = m;

                        }

                        System::Diagnostics::Debug::WriteLine("L_b = " + L_b.ToString() + "   m = " + m.ToString() + "   U_b = " + U_b.ToString());

                } while ((Math::Abs(U_b - L_b) >= acc * Math::Abs(U_b))

                        &&

                        ((Math::Abs(U_b) + Math::Abs(L_b)) >= 1.0e-14)

                        );

                Root = 0.5 * (L_b + U_b);

        }

 

        //     Newton法による根の計算  

        template<class TF, class TDF>

        void TNewton(double & x,                //  根の初期値、戻り値は根 f(x)=c

                double c,                                       //  関数値

                TF & f,                                         //  関数

                TDF & df,                                       //  導関数

                double acc){

                int NStep = 0;

                int ck = 0;

                double x0;

                do {

                        NStep++;

                        if (NStep > 20) {                       //  20回以上繰り返しのとき

                                ck = 1;

                                break;

                        };

                        x0 = x;

                        x = x0 + (c - f(x0)) / df(x0);

                        if (x <= 0.0) x = 0.5 * x0;

                        if (x > x0 * 2.0) x = x0 * 2.0;

                } while ((Math::Abs(x - x0) >= (acc * (Math::Abs(x) + Math::Abs(x0))))

                        &&

                        ((Math::Abs(x) + Math::Abs(x0)) >= 1.0e-14)

                        );

 

                if ((ck == 0) && (x > 1.0e-16)) return;

 

                //   Bisection法で計算

 

                double L_b = 1.0;

                do {

                        L_b *= 0.5;

                } while (f(L_b) >= c);

 

                double U_b = 1.0;

                do {

                        U_b += 1.0;

                } while (f(U_b) <= c);

 

                TBisection<TF>(f, 1.0, c, L_b, U_b, x, acc);

                return;

        }

 

        class Chi2_density{

        public:

                double df;

                double coeff;

                Chi0 chi0;

                Chi2_density(){}

                Chi2_density(double vdf){

                        df = vdf;

                        chi0.df = df;

                        Chi0t chi0t(df);

                        TAdaptiveGL<Chi0t> gl(chi0t);

                        double IntgrlChi0 = gl.integral(0.0, Math::PI / 2.0);

                        coeff = 1.0 / IntgrlChi0;

                }

                void set_df(double vdf){

                        df = vdf;

                        chi0.df = df;

                        Chi0t chi0t(df);

                        TAdaptiveGL<Chi0t> gl(chi0t);

                        double IntgrlChi0 = gl.integral(0.0, Math::PI / 2.0);

                        coeff = 1.0 / IntgrlChi0;

                }

                double operator()(double chi2){

                        double v = chi0(chi2);

                        return v * coeff;

                }

        };

       

 

        class Calc_chi2_for_p {

        public:

                double df;

                CumChi2 cum_chi2;

                Chi2_density chi2_density;

                Calc_chi2_for_p(){}

                Calc_chi2_for_p(double vdf){

                        df = vdf;

                        cum_chi2.setCumChi2(df);

                        chi2_density.set_df(df);

                }

                double operator()(double p){

                        double x2 = 1.0;

                        TNewton<CumChi2, Chi2_density>(x2, p, cum_chi2, chi2_density, 1.0e-12);

 

                        return x2;

                }

        };

 

}

 

#endif

 

 

 

Up