被験者間1要因・被験者内1要因分散分析
被験者内1要因・被験者間1要因分散分析のためのVisual C++プログラムを作成した。この分散分析については<岡本安晴「データ分析のための統計学入門」2009、おうふう;第4章:分散分析>およびreadme.pdfファイルなどを参照されたい。プログラムは、ウェブサイト<テキストファイル入出力>で説明したプログラムに下記のようにコードを書き加えて作成した。
===============================================
//
// 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 a = int::Parse(SeekStr(s, 0));
int b = int::Parse(SeekStr(s, 1));
int n = int::Parse(SeekStr(s, 2));
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++){
while(true){
s = fin->ReadLine();
if
(s->Length > 0)
if (s[0]
== '/') break;
}
for (int i = 0; i < n; i++){
s = fin->ReadLine();
for (int k = 0; k < b; k++)
y[i][j][k] = double::Parse(SeekStr(s,
k));
}
}
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_btwn = 0.0;
for (int i = 0; i
< n; i++)
for (int j = 0; j
< a; j++){
v
= 0.0;
for (int k = 0; k
< b; k++)
v
+= y[i][j][k];
ss_btwn
+= sqr(v);
}
ss_btwn
= ss_btwn / b - 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_sa = ss_btwn - ss_a;
double ss_wthn = ss_total - ss_btwn;
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_sba = ss_wthn - ss_b - ss_ab;
double * sum;
sum
= new double[b];
fout->WriteLine();
fout->WriteLine();
fout->WriteLine("要因A:被験者間要因 要因B:被験者内要因");
for (int j = 0; j
< a; j++){
fout->WriteLine();
fout->WriteLine("要因A-" + (j+1).ToString() + ">");
fout->Write(
String("
").PadLeft(15) );
for (int k = 0; k
< b; k++)
fout->Write(("B-" +
(k+1).ToString())->PadLeft(15));
fout->WriteLine();
double * sum;
sum
= new double[b];
for (int k = 0; k
< b; k++) sum[k] = 0.0;
for (int i = 0; i
< n; i++){
fout->Write(
String("
").PadLeft(15) );
for (int k = 0; k
< b; k++){
fout->Write(y[i][j][k].ToString()->PadLeft(15));
sum[k]
+= y[i][j][k];
}
fout->WriteLine();
}
fout->WriteLine("-平均-");
fout->Write(
String("
").PadLeft(15) );
for (int k = 0; k
< b; k++)
fout->Write((sum[k]/n).ToString("F3")->PadLeft(15));
fout->WriteLine();
}
fout->WriteLine();
fout->WriteLine();
fout->WriteLine(String("SV").PadLeft(15) + String("SS").PadLeft(15) + String("df").PadLeft(10) + String("MS").PadLeft(15) + String("F").PadLeft(15));
fout->WriteLine(String("Between S").PadLeft(15) +
ss_btwn.ToString("F3")->PadLeft(15)
+ (a*n-1).ToString()->PadLeft(10));
fout->WriteLine(String("A").PadLeft(15) + ss_a.ToString("F3")->PadLeft(15) +
(a-1).ToString()->PadLeft(10) + (ss_a/(a-1)).ToString("F3")->PadLeft(15) +
((ss_a/(a-1))
/ (ss_sa/(a*(n-1.0)))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("S/A").PadLeft(15) + ss_sa.ToString("F3")->PadLeft(15) +
(a*(n-1)).ToString()->PadLeft(10) + (ss_sa/(a*(n-1.0))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("Within S").PadLeft(15) +
ss_wthn.ToString("F3")->PadLeft(15)
+ (a*n*(b-1.0)).ToString()->PadLeft(10));
fout->WriteLine(String("B").PadLeft(15) + ss_b.ToString("F3")->PadLeft(15) +
(b-1).ToString()->PadLeft(10) +
(ss_b/(b-1)).ToString("F3")->PadLeft(15) + ((ss_b/(b-1)) /
(ss_sba/(a*(b-1)*(n-1.0)))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("AB").PadLeft(15) + ss_ab.ToString("F3")->PadLeft(15) +
((a-1)*(b-1)).ToString()->PadLeft(10) +
(ss_ab
/ ((a-1)*(b-1))).ToString("F3")->PadLeft(15)
+ ((ss_ab/((a-1)*(b-1))) / (ss_sba/(a*(b-1)*(n-1.0)))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("SB/A").PadLeft(15) + ss_sba.ToString("F3")->PadLeft(15) +
(a*(b-1)*(n-1)).ToString()->PadLeft(10) +
(ss_sba/(a*(b-1)*(n-1))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("Total").PadLeft(15) +
ss_total.ToString("F3")->PadLeft(15)
+ (a*b*n - 1).ToString()->PadLeft(10));
fout->Close();
MessageBox::Show(saveFileDialog1->FileName
+ " was saved.");
Close();
}
===============================================
このプログラムを実行すると図1のウィンドウが表示される。
図1
「button1」ボタンのクリックで入力データ名設定用ダイアログウィンドウが図2のように表示される。
図2
入力データファイル名を指定して「開く」ボタンをクリックすると、計算結果出力用のファイル名設定を求めるダイアログウィンドウが表示される(図3)。
図3
出力はテキストファイルとして書き出されるので、ファイル名の拡張子は「.txt」としておく。出力ファイル名の設定後、「保存」ボタンをクリックすると計算がはじまり、計算終了後図4のメッセージウィンドウが表示される。
図4
メッセージウィンドウの「OK」ボタンのクリックでプログラムが終了する。
入力データは、図5に示すようにスラッシュ/で始まる行の次の行に、まず2つの要因の水準数とセル内データ数(被験者間要因Aの各水準内の被験者数)を書く。
図5
次の行から、第1要因(Aで表わしておく)の各水準ごとに、スラッシュで始まる行に続けて第2要因(Bで表わしておく)の水準が列に対応するようにデータを書く。行は各被験者の要因Bの水準にわたるデータである。図5の場合、要因Aの第1水準A1の第1被験者の要因Bの第1水準B1における値は5, 第2水準B2における値は6である。要因Aの第3水準A3における第3被験者の水準B1の値は2、水準B2の値は6である。
図5のファイルを入力データとしたときの出力ファイルは次のようになっている。
============ 出力ファイル例:ここから ====================
Data
file...F:\yasuharu\www\LaCoocan\introprg\ANOVA1btwn1wthn\anova1btwn1wthn\anova1btwn1wthn\DataANOVA1btwn1wthn.txt
要因A:被験者間要因 要因B:被験者内要因
要因A-1>
B-1
B-2
5
6
4
8
6
7
-平均-
5.000
7.000
要因A-2>
B-1
B-2
8 9
6
7
7
8
-平均-
7.000
8.000
要因A-3>
B-1
B-2
3
5
1
3
2
6
-平均-
2.000
4.667
SV
SS
df
MS
F
Between S
63.778 8
A
53.444
2
26.722
15.516
S/A
10.333
6
1.722
Within
S
22.500
9
B
16.056
1
16.056
22.231
AB
2.111
2
1.056
1.462
SB/A
4.333
6
0.722
Total
86.278
17
============ 出力ファイル例:ここまで========================
プログラム・ファイルは圧縮ファイルanova1btwn1wthn.zipとしてまとめた。ファイル名anova1btwn1wthn.zipをクリックしてダウンロードしたものをマウスの右ボタンクリックで表示されるメニュ「解凍」あるいは「展開」などを選ぶと解凍できる。解凍したものはVisual C++などで開いてビルド実行することができる。実行形式ファイルanova1btwn1wthn.exeも用意したので、ファイル名anova1btwn1wthn.exeをクリックしてダウンロード実行することができる。実行形式ファイルは.NET Framework3.5対応である。
なお、F値に対応する確率を求めるVisual C++プログラムはウェブサイト<エフ分布>に用意した。