被験者内2要因分散分析
被験者内2要因分散分析のための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 * 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("Subject").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(
(i+1).ToString()->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();
}
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_s = 0.0;
for (int i = 0; i
< n; i++){
v
= 0.0;
for (int j = 0; j
< a; j++)
for (int k = 0; k
< b; k++)
v
+= y[i][j][k];
ss_s
+= sqr(v);
}
ss_s
= ss_s / (a * b) - 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_as = 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_as
+= sqr(v);
}
ss_as
= ss_as / b - ss_c - ss_a - ss_s;
double ss_bs = 0.0;
for (int i = 0; i
< n; i++)
for (int k = 0; k
< b; k++){
v
= 0.0;
for (int j = 0; j
< a; j++)
v
+= y[i][j][k];
ss_bs
+= sqr(v);
}
ss_bs
= ss_bs / a - ss_c - ss_b - ss_s;
double ss_abs = ss_total - ss_a - ss_b - ss_s - ss_ab
- ss_as - ss_bs;
fout->WriteLine();
fout->WriteLine();
fout->WriteLine(String("SV").PadLeft(10) + String("SS").PadLeft(15) + String("df").PadLeft(10) + String("MS").PadLeft(15) + String("F").PadLeft(15));
fout->WriteLine(String("S").PadLeft(10) + ss_s.ToString("F3")->PadLeft(15) +
(n-1).ToString()->PadLeft(10) +
(ss_s
/ (n -1)).ToString("F3")->PadLeft(15));
fout->WriteLine(String("SSw.s").PadLeft(10) + (ss_total -
ss_s).ToString("F3")->PadLeft(15)
+ (n * (a * b - 1)).ToString()->PadLeft(10));
fout->WriteLine(String("A").PadLeft(10) + ss_a.ToString("F3")->PadLeft(15) +
(a-1).ToString()->PadLeft(10) +
(ss_a
/ (a - 1)).ToString("F3")->PadLeft(15)
+
((ss_a
/ (a - 1)) / (ss_as / ((a - 1) * (n - 1.0)))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("AS").PadLeft(10) + ss_as.ToString("F3")->PadLeft(15) + ((a - 1) * (n -
1)).ToString()->PadLeft(10) +
(ss_as
/ ((a - 1) * (n - 1))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("B").PadLeft(10) + ss_b.ToString("F3")->PadLeft(15) +
(b-1).ToString()->PadLeft(10) +
(ss_b
/ (b - 1)).ToString("F3")->PadLeft(15)
+
((ss_b
/ (b - 1)) / (ss_bs / ((b - 1) * (n - 1.0)))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("BS").PadLeft(10) + ss_bs.ToString("F3")->PadLeft(15) + ((b - 1) * ( n -
1)).ToString()->PadLeft(10) +
(ss_bs
/ ((b - 1) * (n - 1))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("AB").PadLeft(10) + 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_abs / ((a - 1) * (b - 1) * (n - 1.0)))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("ABS").PadLeft(10) + ss_abs.ToString("F3")->PadLeft(15) + ((a - 1) * (b -
1) * (n - 1)).ToString()->PadLeft(10) +
(ss_abs
/ ((a - 1) * (b - 1) * (n - 1))).ToString("F3")->PadLeft(15));
fout->WriteLine(String("Total").PadLeft(10) +
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つの要因の水準数と被験者数を書く。
図5
次の行から、第1要因(Aで表わしておく)の各水準ごとに、スラッシュで始まる行に続けて第2要因(Bで表わしておく)の水準が列に対応するようにデータを書く。行は各被験者の要因Bの水準にわたるデータである。また、第1要因Aの各水準におけるデータ行は被験者に対応している。第1被験者の水準A1、B1における値は37、同じ第1被験者の水準A3、水準B2における値は59である。第5被験者は水準A1、水準B2に対する値は56、水準A2,水準B1に対する値は46である。
図5のファイルを入力データとしたときの出力ファイルは次のようになっている。
============ 出力ファイル例:ここから ====================
Data
file...F:\yasuharu\www\LaCoocan\introprg\ANOVA2wthn\anova2wthn\anova2wthn\DataANOVA2wthn.txt
要因A:被験者内要因 要因B:被験者内要因
要因A-1
Subject
B-1
B-2
1
37
41
2
42
47
3
45
46
4
37
50
5
40
56
6
38
42
-平均-
39.833
47.000
要因A-2
Subject
B-1
B-2
1
46
53
2
48
56
3
48
53
4 47
55
5
46
55
6
49
56
-平均-
47.333
54.667
要因A-3
Subject
B-1
B-2
1
49 59
2
55
59
3
53
53
4
48
57
5
47
59
6
53
62
-平均-
50.833
58.167
SV
SS
df
MS
F
S
49.139
5
9.828
SSw.s
1515.167 30
A
770.389
2
385.194
30.504
AS
126.278 10
12.628
B
476.694
1
476.694
24.878
BS
95.806
5
19.161
AB
0.056
2
0.028
0.006
ABS
45.944 10
4.594
Total
1564.306 35
============ 出力ファイル例:ここまで========================
プログラム・ファイルは圧縮ファイルanova2wthn.zipとしてまとめた。ファイル名anova2wthn.zipをクリックしてダウンロードしたものをマウスの右ボタンクリックで表示されるメニュ「解凍」あるいは「展開」などを選ぶと解凍できる。解凍したものはVisual C++などで開いてビルド実行することができる。実行形式ファイルanova2wthn.exeも用意したので、ファイル名anova2wthn.exeをクリックしてダウンロード実行することができる。実行形式ファイルは.NET Framework3.5対応である。
なお、F値に対応する確率を求めるVisual C++プログラムはウェブサイト<エフ分布>に用意した。