Up

被験者間2要因分散分析

非繰り返し2要因分散分析

 

被験者間2要因分散分析(岡本安晴「データ分析のための統計学入門」おうふう)のVisual C++/win32プログラムを作成した。なお、Win32コンソールアプリケーションの新規作成については<Win32コンソールアプリケーションの新規作成>で、C++の標準入出力(コンソール入出力)については<標準入出力cincout>で、C++におけるテキストファイル入出力については<テキストファイル入出力>で説明している。

 プログラムの実行例を図1に示す。

図1

 

入力ファイルはプログラム・ソースコード・ファイル*.cppと同じフォルダに用意する。

入力データファイル設定のソースコードは以下のようになっている。

 

              cout << "入力データファイル = " ;

              string ifnm;

              cin >> ifnm;

              ifstream fin( ifnm );

             

              if ( ! fin){                                                        //            入力ファイルの設定が失敗するとfinfalseを返す。

                            cout << "入力ファイルエラー" << endl;

                            cout << "何か文字を入力して終了。" << endl;

                            string s;

                            cin >> s;

                            return 9;

              }

 

入出力ストリーム・オブジェクトの変数finを条件式に用いると、ストリームに何かエラーがあるとfalseが返される。

 

入力ファイルは図2の形式で用意する。

図2

 

finによる入力は空白あるいは改行で区切られた文字列単位に行われ、空白行は読み飛ばされる。図2では、4行目からがfinによる読み込みの対象となる。4行目の3つの数値は、要因A、要因Bの水準数、およびセル内のデータ数を表す。6行目から要因Aの水準ごとにデータがまとめられ、要因Aの水準ごとに空白行で区切られている。横方向に要因Bの水準ごとにまとめられている。すべてのデータ(図2の場合は、個のデータ)が書かれた後は読み込みの対象とならないので、コメントを自由に書くことができる。図2では、上のデータの記載形式が書かれている。

エディタでデータを新しく用意したときは、保存してからプログラムで読み込む。エディタの画面に打ち込んだだけでは、その内容はファイルに反映されない。

図2の形式のデータファイルに対する読み込みは、次のコードによって行っている。

 

              int a, b, n;

              fin >> a >> b >> n;

 

              double *** y;

              y = new double **[n];

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

                            y[i] = new double*[a];

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

                                          y[i][j] = new double[b];

              }

 

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

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

                                          for (int k = 0; k < b; k++)

                                                        fin >> y[i][j][k];

 

計算を終えて結果の書き出しが終了すると「何か文字を入力して終了」と表示されるので、適当な文字キーを押してEnterキーを押すとプログラムの終了となる。この部分は以下のコードによって処理されている。

 

              fout.close();

              cout << endl << "計算終了" << endl;

              cout << "何か文字を入力して終了" << endl;

              string ckstr;

              cin >>ckstr;

              return 0;

 

出力ファイルもファイル名を図1のように設定すると、プログラムソースコードファイル*.cppと同じフォルダ内に作成される。図2のデータでプログラムを実行したときの出力ファイルをVisualC++のエディタで開くと図3のようになっている。

図3

 

要因Bの水準数が2ケタになっても右側で揃うように、次のようなコードで書き出している。

 

                            for (int k = 0; k < b; k++){

                                          ostringstream sout;

                                          sout << "B-" << k+1;

                                          fout << setw(15) << sout.str();

                                          sum[k] = 0.0;

                            }

 

ストリームostringstream型は文字列への書き出し、すなわちメモリ上への書き出しを行う出力用の文字列ストリームであり、書き出された結果はstr( )関数によって文字列として取り出せる。

fout << setw(15)

におけるsetw(15)は、書式(フォーマット)を指定するマニピュレータと呼ばれているものの1つで、setw( k )を出力すると、setw(k)に続く出力はk文字分の長さになるように空白文字を補って出力される。

平均値は、小数点以下2桁の出力に揃えられているが、これは以下のコードによる。

 

                            fout << "平均" << endl;

                            for (int k = 0; k < b; k++)

                                          fout << setprecision(2) << fixed << setw(15) << sum[k]/n;

 

setprecision( s ) << fixed」と続けて出力すると、それ以降の実数値の出力は小数点以下s桁で書き出される。この設定を初期状態に戻すために、書き出し後

                            fout << resetiosflags(ios_base::floatfield);

を実行している。

 分散分析表は、上で説明したマニピュレータを用いて図3に示されているように右側で揃えた書き出しを行っている。

 

プログラムソースコード全体は以下の通りである。

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

#include "stdafx.h"                         //            Visual C++が勝手に用意するもの。削除するとエラーになる。

 

#include <iostream>                       //            cin, coutの使用のため

#include <fstream>                        //            ifstream, ifstreamの使用のため

#include <iomanip>                        //            setwなどの使用のため

#include <string>                           //            string型の使用のため

#include <sstream>                        //            文字列ストリーム使用のため

 

using namespace std;                     //            cin, coutなどが属する名前空間

 

double sqr( double v ){

                            return  v * v;

}

 

int _tmain(int argc, _TCHAR* argv[])

{

              cout << "入力データファイル = " ;

              string ifnm;

              cin >> ifnm;

              ifstream fin( ifnm );

             

              if ( ! fin){                                                        //            入力ファイルの設定が失敗するとfinfalseを返す。

                                          cout << "入力ファイルエラー" << endl;

                                          cout << "何か文字を入力して終了。" << endl;

                                          string s;

                                          cin >> s;

                                          return 9;

              }

 

              int a, b, n;

              fin >> a >> b >> n;

 

              double *** y;

              y = new double **[n];

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

                            y[i] = new double*[a];

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

                                          y[i][j] = new double[b];

              }

 

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

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

                                          for (int k = 0; k < b; k++)

                                                        fin >> y[i][j][k];

             

              fin.close();

             

              //

              //                                        平方和の計算

              //

              double v = 0.0;

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

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

                                          for (int k = 0; k < b; k++)

                                                        v += y[i][j][k];

              double rn = n;

              double ss_c = sqr(v) / (rn * a * b);

 

              v = 0.0;

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

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

                                          for (int k = 0; k < b; k++)

                                                        v += sqr(y[i][j][k]);

              double ss_total = v - ss_c;

 

              double ss_a = 0.0;

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

                            v = 0.0;

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

                                          for (int k = 0; k < b; k++)

                                                        v += y[i][j][k];

                            ss_a += sqr(v);

              }

              ss_a = (ss_a / (rn * b)) - ss_c;

 

              double ss_b = 0.0;

              for (int k = 0; k < b; k++){

                            v = 0.0;

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

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

                                                        v += y[i][j][k];

                            ss_b += sqr(v);

              }

              ss_b = (ss_b / (rn * a)) - ss_c;

 

              double ss_ab = 0.0;

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

                            for (int k = 0; k < b; k++){

                                          v = 0.0;

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

                                                        v += y[i][j][k];

                                          ss_ab += sqr(v);

                            }

              ss_ab = (ss_ab / rn) - ss_c - ss_a - ss_b;

 

              double ss_err = ss_total - ss_a - ss_b - ss_ab;

 

              double * sum;

              sum = new double[b];

                                                       

              //

              //                          出力ファイルの設定

              //

              cout << "出力ファイル名 = ";

              string ofnm;

              cin >> ofnm;

              ofstream fout( ofnm );

              fout << "入力データ..." << ifnm << endl << endl;

 

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

                            fout << endl << "A-" << j+1 << endl;

                            for (int k = 0; k < b; k++){

                                          ostringstream sout;

                                          sout << "B-" << k+1;

                                          fout << setw(15) << sout.str();

                                          sum[k] = 0.0;

                            }

                            fout << endl;

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

                                          for (int k = 0; k < b; k++){

                                                        fout << setw(15) << y[i][j][k];

                                                        sum[k] += y[i][j][k];

                                          }

                                          fout << endl;

                            }

 

                            fout << "平均" << endl;

                            for (int k = 0; k < b; k++)

                                          fout << setprecision(2) << fixed << setw(15) << sum[k]/n;

                            fout << endl;

                            fout << resetiosflags(ios_base::floatfield);

              }

                                                                     

              fout << endl << endl;

              fout << setw(10) << "SV" << setw(15) << "SS" << setw(10) << "df" << setw(15) << "MS" <<setw(15) << "F" << endl;

              fout << setprecision(3) << fixed;

              fout << setw(10) << "A" << setw(15) << ss_a << setw(10) << a-1 << setw(15) << ss_a/(a-1)

                            << setw(15) << (ss_a/(a-1)) / (ss_err/(a * b * (n-1.0))) << endl;

              fout << setw(10) << "B" << setw(15) << ss_b << setw(10) << b-1 << setw(15) << ss_b/(b-1)

                            << setw(15) << (ss_b/(b-1)) / (ss_err/(a * b * (n-1.0))) << endl;

              fout << setw(10) << "AB" << setw(15) << ss_ab << setw(10) << (a-1)*(b-1) << setw(15) << ss_ab/((a-1.0)*(b-1.0))

                            << setw(15) << (ss_ab/((a-1.0)*(b-1.0))) / (ss_err/(a * b * (n-1.0))) << endl;

              fout << setw(10) << "S/AB" << setw(15) << ss_err << setw(10) << a*b*(n-1) << setw(15) << ss_err / (a * b * (n - 1.0))

                            << endl;

              fout << setw(10) << "Total" << setw(15) << ss_total << setw(10) << a * b * n - 1 << endl;

                           

              fout.close();

              cout << endl << "計算終了" << endl;

              cout << "何か文字を入力して終了" << endl;

              string ckstr;

              cin >>ckstr;

              return 0;

}

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

 

 プログラムソースコードファイルなどをまとめたものは圧縮ファイルanova.zipとして用意した。圧縮ファイル名anova.zipをクリックしてダウンロードすることが出来る。ダウンロードした圧縮ファイルanova.zipはマウスの右ボタンクリックで表示されるメニュから「展開」あるいは「解凍」を選ぶと解凍できる。解凍したファイルはVisual C++2010で開くことができる。

 

 Visual C++プログラミングの入門書として<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房>を上梓した。

 

Up