第34章 簡単な検定プログラム


今回はC++を使って、簡単な検定プログラムを作ってみます。

A市とB市の20歳の男子の身長の平均が168.0cmと169.5cmだったとします。 単純にB市の20歳男子の身長の方が高いという結論は出せません。 通常この2群間の平均値に差がないと仮定して、この仮説が否定されたとき 2群間に差があると結論します。 このような検定法は星の数だけあります。それぞれ前提となる条件がことなり、 間違った検定法を用いると誤った結果を導くことになるので注意が必要です。 詳しくは統計学の本を調べてください。



2つの平均値を比較する場合、もっとも簡単な検定法がt検定です。 これは、2つの平均値からt値を求めて2群間に差があるのかどうかを検定します。 いろいろ前提となる条件があるのですが、ここではすべて無視します。

2つのグループの平均値、標準誤差を調べます。標準誤差は平均値を 個数のルートで割ったものです。2群の平均値の差をそれぞれの標準誤差の2乗の 和のルートで割ったものがt値となります。個数が多い場合この値が1.96より大きい場合 信頼度95%で差があるとします。2.576より大きい場合信頼度は99%となります。 要するに2つの平均値に差がある場合、偶然そのようになる確率が5%, 1%以下である と考えればよいわけです。

では、プログラムを見てみましょう。前章で作ったクラスを少しだけ改変します。

// statics02.cpp #include <iostream.h> #include <conio.h> #include <math.h> class tokei { double *pdata, sum, sum2, mean, sd, se; int no; public: tokei(); ~tokei(); int correct(); double tokei_output(int); };

クラスのメンバにseというのが増えました。これが標準誤差です。 また、外部に統計量を知らせるための関数tokei_outputというメンバ関数も 作ることにします。

tokei::tokei() { int i; sum = 0; sum2 = 0; while (1) { cout << "データの個数 = "; cin >> no; if (no < 2) { cout << "データの個数は2つ以上必要です" << endl; } else { break; } } pdata = new double[no]; for (i = 0; i < no; i++) { cout << "[" << i << "] = "; cin >> *(pdata + i); sum += *(pdata + i); sum2 += pow(*(pdata + i), 2); } mean = sum / no; sd = sqrt((sum2 - no * pow(mean, 2)) / no); se = sd / sqrt(no); }

コントスラクタの中身です。seの計算をしている部分が増えました。

tokei::~tokei() { delete []pdata; } int tokei::correct() { int cno, i; cout << "データ番号 --> "; cin >> cno; if (cno >= no) { cout << "データ番号が不正です" << endl; return -1; } cout << "[" << cno << "] = "; cin >> *(pdata + cno); sum = 0; sum2 = 0; for (i = 0; i < tokei::no; i++) { sum += *(pdata + i); sum2 += pow(*(pdata + i), 2); } mean = sum / no; sd = sqrt((sum2 - no * pow(mean, 2)) / no); se = sd / sqrt(no); return 0; }

データを修正したら、それぞれの統計量を計算し直します。

double tokei::tokei_output(int id) { double ans; switch (id) { case 0: ans = (double)no; break; case 1: ans = sum; break; case 2: ans = sum2; break; case 3: ans = mean; break; case 4: ans = sd; break; case 5: ans = se; break; default: cout << endl << "Error!" << endl; ans = 0; break; } return ans; }

引数によって戻り値が異なります。これによってクラス外から 基本統計量を知ることができます。

int main() { int id, i; int end = 0; double t, mean1, mean2, se1, se2; static char *komoku[] = {"個数", "合計", "平方和", "平均", "標準偏差", "標準誤差"}; cout << "グループ1" << endl; tokei MyTokei1; cout << endl; cout << "グループ2" << endl; tokei MyTokei2; cout << endl; while (1) { cout << endl; cout << "***********************************"<< endl; cout << "1.各グループの基本統計量" << endl; cout << "2.グループ1データの修正" << endl; cout << "3.グループ2データの修正" << endl; cout << "4.グループ間の平均値の比較" << endl; cout << "0. 終了" << endl; cout << "***********************************"<< endl; cout << endl; cout << "番号選択-->"; cin >> id; switch (id) { case 0: end = 1; break; case 1: cout << "****グループ1****" << endl; for (i = 0; i <= 5; i++) { cout << komoku[i] << " = " << MyTokei1.tokei_output(i); cout << endl; } cout << endl; getch(); cout << "****グループ2****" << endl; for (i = 0; i <= 5; i++) { cout << komoku[i] << " = " << MyTokei2.tokei_output(i); cout << endl; } cout << endl; getch(); break; case 2: MyTokei1.correct(); break; case 3: MyTokei2.correct(); break; case 4: mean1 = MyTokei1.tokei_output(3); mean2 = MyTokei2.tokei_output(3); se1 = MyTokei1.tokei_output(5); se2 = MyTokei2.tokei_output(5); t = mean1 -mean2; if (t < 0) t *= -1; if (pow(se1, 2) + pow(se2, 2) == 0) { cout << "分母が0となります" << endl; break; } t = t / sqrt(pow(se1, 2) + pow(se2, 2)); cout << "t値 = " << t << endl; cout << endl; break; default: cout << "番号の間違いです" << endl; break; } if (end == 1) break; } return 0; }

tokei MyTokei1;
tokei MyTokei2;

としただけで、それぞれのグループの平均値などが求まっています。

あとは無限ループの中でメニュー番号に従って仕事をしています。0を選択すると ループを抜けてプログラムを終了します。

データの個数が多い場合、1つ1つのデータをキー入力するのは大変です。間違いも多くなります。 テキストファイルにデータを記入しておいて、これを読み出すようにすると少しは 楽になるでしょう。このようなプログラムも考えてみてください。


[C++Index] [総合Index] [Previous Chapter] [Next Chapter]

Update May/16/2000 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。