上へ

カイ2乗検定

分割表の分析

 

分割表(contingency table)のカイ二乗検定を行うVisual C++プログラムを作成した。これらのカイ2乗検定については<岡本安晴「データ分析のための統計学入門」2009、おうふう;第3章:検定>において、「分布の違いの検定」および「カテゴリの独立性の検定」の2つの場合が説明されているが、計算式は同じなので両方の場合に共通に用いることができるプログラムとして用意した。プログラムは、ウェブサイト<テキストファイル入出力>で説明したプログラムに下記のようにコードを書き加えて作成した。

===============================================

        //

        //              pos 番目の文字列の取り出し

        //

        String ^ SeekStr( String ^ str, int pos ){

                String ^ vstr = "";

                array<wchar_t> ^ separator = { ' ', '\t', ',',' ','/' };

                array<String ^> ^ ary_str;

                ary_str = str->Split( separator );

                int L = ary_str->Length;

                int ckp = -1;

                int tmpPos = 0;

                do {

                        if (ary_str[tmpPos]->Length > 0) ckp++;

                        tmpPos++;

                } while ((ckp != pos) && (tmpPos < L) );

                if (ckp == pos) vstr = ary_str[tmpPos-1];

 

                return vstr;

        }

 

        double sqr( double v ){

                        return v * v;

        }

       

        private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {

                                 //

                                 //             入出力ファイルの名の設定

                                 //

                                 openFileDialog1->Title = "入力データファイル名";

                                 if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::Cancel) return;

                                 saveFileDialog1->Title = "出力ファイル名";

                                 if (saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::Cancel) return;

 

                                 using namespace System::IO;

                                 //

                                 //             入力ストリームと出力ストリームの設定

                                 //

                                 StreamReader ^ fin = gcnew StreamReader( openFileDialog1->FileName, System::Text::Encoding::GetEncoding("shift-jis") );

                                 StreamWriter ^ fout = gcnew StreamWriter( saveFileDialog1->FileName, false, System::Text::Encoding::GetEncoding("shift-jis") );

 

                                 fout->WriteLine("Data file..." + openFileDialog1->FileName);

                                 fout->WriteLine();

 

                                 String ^s;

                                 while(true){

                                         s = fin->ReadLine();

                                         if (s->Length > 0)

                                                 if (s[0] == '/') break;

                                 }

                                 s = fin->ReadLine();

                                 int r = int::Parse(SeekStr(s, 0));

                                 int c = int::Parse(SeekStr(s, 1));

                                 double ** O, ** E;

                                 O = new double*[r];

                                 E = new double*[r];

                                 for (int i = 0; i < r; i++){

                                        O[i] = new double[c];

                                        E[i] = new double[c];

                                 }

                                 for (int i = 0; i < r; i++){

                                         s = fin->ReadLine();

                                         for (int j = 0; j < c; j++)

                                                 O[i][j] = double::Parse(SeekStr(s, j));

                                 }     

                                 fin->Close();

 

                                 double * R, * C;

                                 R = new double[r];

                                 for (int i = 0; i < r; i++){

                                        R[i] = 0.0;

                                        for (int j = 0; j < c; j++) R[i] += O[i][j];

                                 }

                                 C = new double[c];

                                 for (int j = 0; j < c; j++){

                                        C[j] = 0.0;

                                        for (int i = 0; i < r; i++) C[j] += O[i][j];

                                 }

                                 int N = 0;

                                 fout->WriteLine("Data...");

                                 for (int i = 0; i < r; i++){

                                         fout->Write(String(" ").PadLeft(10));

                                         for (int j = 0; j < c; j++)

                                                 fout->Write(O[i][j].ToString()->PadLeft(10));

                                         fout->WriteLine(("sum(" + R[i].ToString() + ")")->PadLeft(15));

                                         N += R[i];

                                 }

                                 fout->WriteLine();

                                 fout->Write(String("sum =").PadLeft(10));

                                 for (int j = 0; j < c; j++)

                                         fout->Write(C[j].ToString()->PadLeft(10));

                                 fout->WriteLine(N.ToString()->PadLeft(15));

 

                                 for (int i = 0; i < r; i++)

                                         for (int j = 0; j < c; j++)

                                                 E[i][j] = R[i] * C[j] / N;

                                 double chi2 = 0.0;

                                 for (int i = 0; i < r; i++)

                                         for (int j = 0; j < c; j++)

                                                 chi2 += sqr(O[i][j] - E[i][j]) / E[i][j];

 

                                 fout->WriteLine();

                                 fout->WriteLine("Chi-squared = " + chi2.ToString("F5") + "       df = " + ((r-1)*(c-1)).ToString());

 

                                 fout->Close();

                                 MessageBox::Show(saveFileDialog1->FileName + " was saved.");

                                 Close();

                         }

===============================================

このプログラムを実行すると図1のウィンドウが表示される。

図1

 

button1」ボタンのクリックで入力データ名設定用ダイアログウィンドウが図2のように表示される。

図2

 

入力データファイル名を指定して「開く」ボタンをクリックすると、計算結果出力用のファイル名設定を求めるダイアログウィンドウが表示される(図3)。

図3

 

出力はテキストファイルとして書き出されるので、ファイル名の拡張子は「.txt」としておく。出力ファイル名の設定後、「保存」ボタンをクリックすると計算がはじまり、計算終了後図4のメッセージウィンドウが表示される。

図4

 

メッセージウィンドウの「OK」ボタンのクリックでプログラムが終了する。

入力データは、図5に示すようにスラッシュ/で始まる行の次の行に、まず分割表の行数と列数を書く。

図5

 

次の行から、分割表に対応する形でデータを書く。

図5のファイルを入力データとしたときの出力ファイルは次のようになっている。

 

============ 出力ファイル例:ここから ====================

Data file...F:\yasuharu\www\LaCoocan\introprg\chi2_xtable\chi2table\chi2table\DataCk.txt

 

Data...

                  28        32        24        30        32        33       sum(179)

                  26        29        26        26        22        28       sum(157)

                  18        19        32        33        26        32       sum(160)

 

     sum =        72        80        82        89        80        93            496

 

Chi-squared = 8.61129       df = 10

============ 出力ファイル例:ここまで========================

 

プログラム・ファイルは圧縮ファイルchi2table.zipとしてまとめた。ファイル名chi2table.zipをクリックしてダウンロードしたものをマウスの右ボタンクリックで表示されるメニュ「解凍」あるいは「展開」などを選ぶと解凍できる。解凍したものはVisual C++などで開いてビルド実行することができる。実行形式ファイルchi2table.exeも用意したので、ファイル名chi2table.exeをクリックしてダウンロード実行することができる。実行形式ファイルは.NET Framework3.5対応である。

なお、値に対応する確率を求めるVisual C++プログラムはウェブサイト<カイ2乗分布>に用意した。

 

上へ