被験者間2要因分散分析
非繰り返し2要因分散分析
被験者間2要因分散分析(岡本安晴「データ分析のための統計学入門」おうふう)のVisual C++/win32プログラムを作成した。なお、Win32コンソールアプリケーションの新規作成については<Win32コンソールアプリケーションの新規作成>で、C++の標準入出力(コンソール入出力)については<標準入出力cinとcout>で、C++におけるテキストファイル入出力については<テキストファイル入出力>で説明している。
プログラムの実行例を図1に示す。
図1
入力ファイルはプログラム・ソースコード・ファイル*.cppと同じフォルダに用意する。
入力データファイル設定のソースコードは以下のようになっている。
cout << "入力データファイル = " ;
string ifnm;
cin >> ifnm;
ifstream fin( ifnm );
if ( ! fin){ // 入力ファイルの設定が失敗するとfinはfalseを返す。
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){ // 入力ファイルの設定が失敗するとfinはfalseを返す。
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++プログラミング入門」勁草書房>を上梓した。