回帰分析
単回帰
単回帰モデル(独立変数が1個の場合の回帰モデル)による2変量データの分析プログラムを作成した。回帰モデルについては<岡本安晴「データ分析のための統計学入門」2009、おうふう;第2章:統計量>などを参照されたい。プログラムは、ウェブサイト<テキストファイル入出力>で説明したプログラムに下記のようにコードを書き加えて作成した。
===============================================
//
// 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;
button1->Enabled = false;
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;
}
String ^ LX, ^ LY;
s = fin->ReadLine();
LX = SeekStr(s, 0);
LY = SeekStr(s, 1);
int n =
0;
while(true){
s = fin->ReadLine();
if (s[0]
== '/') break;
n++;
}
fin->Close();
fin = gcnew
StreamReader( openFileDialog1->FileName,
System::Text::Encoding::GetEncoding("shift-jis")
);
while(true){
s = fin->ReadLine();
if
(s->Length > 0)
if (s[0]
== '/') break;
}
s = fin->ReadLine();
double *
x, * y;
x = new double[n];
y = new double[n];
for (int i = 0; i < n; i++){
s = fin->ReadLine();
x[i] = double::Parse(SeekStr(s,
0));
y[i] = double::Parse(SeekStr(s,
1));
}
fin->Close();
fout->WriteLine("Data...");
fout->WriteLine(LX->PadLeft(15) +
LY->PadLeft(20));
for (int i = 0; i < n; i++)
fout->WriteLine(String("x[").PadLeft(10) + (i+1).ToString() + "] = " + x[i].ToString()->PadLeft(7)
+
String("y[").PadLeft(10)
+ (i+1).ToString() + "] = " +
y[i].ToString()->PadLeft(7));
double sx
= 0.0, sy = 0.0;
for (int i = 0; i < n; i++){
sx
+= x[i];
sy
+= y[i];
}
double
MeanX = sx / n;
double
MeanY = sy / n;
double ssx
= 0.0, ssy = 0.0, sxy = 0.0, sRxRy = 0.0, ssRx = 0.0;
for (int i = 0; i < n; i++){
ssx
+= sqr(x[i] - MeanX);
ssy
+= sqr(y[i] - MeanY);
sxy
+= (x[i] - MeanY) * (y[i] - MeanY);
sRxRy
+= x[i] * y[i];
ssRx += sqr(x[i]);
}
double
SDX = Math::Sqrt(ssx / n);
double
SDY = Math::Sqrt(ssy / n);
fout->WriteLine();
fout->WriteLine("X==<" + LX + ">");
fout->WriteLine("Xの平均 = " + MeanX.ToString("F5"));
fout->WriteLine("Xの分散 = " + (ssx/n).ToString("F5"));
fout->WriteLine("Xの標準偏差 = " + SDX.ToString("F5"));
fout->WriteLine("Xの不偏分散 = " +
(ssx/(n-1)).ToString("F5"));
fout->WriteLine("Xの不偏分散の平方根= " +
Math::Sqrt(ssx/(n-1)).ToString("F5"));
fout->WriteLine();
fout->WriteLine("Y==<" + LY + ">");
fout->WriteLine("Yの平均 = " + MeanY.ToString("F5"));
fout->WriteLine("Yの分散 = " + (ssy/n).ToString("F5"));
fout->WriteLine("Yの標準偏差 = " + SDY.ToString("F5"));
fout->WriteLine("Yの不偏分散 = " +
(ssy/(n-1)).ToString("F5"));
fout->WriteLine("Yの不偏分散の平方根= " +
Math::Sqrt(ssy/(n-1)).ToString("F5"));
//
//
共分散
//
double
cov = sxy / n;
fout->WriteLine();
fout->WriteLine("共分散 = " + cov.ToString("F5"));
//
//
相関係数
//
double r
= sxy / Math::Sqrt(ssx * ssy);
fout->WriteLine("相関係数= " + r.ToString("F5"));
/*************************************
y
= a * x + b;
**************************************/
double a =
(n * sRxRy - sx * sy) / (n * ssRx - sqr(sx));
double b
= (ssRx * sy - sx * sRxRy) / (n * ssRx - sqr(sx));
fout->WriteLine();
fout->WriteLine("a = " + a.ToString("F5"));
fout->WriteLine("b = " + b.ToString("F5"));
fout->WriteLine();
fout->WriteLine("Y(" + LY + ")
= " + a.ToString("F3")
+ " * X(" + LX + ") + (" + b.ToString("F3") + ")");
fout->WriteLine();
fout->WriteLine("決定係数 = " + (r*r).ToString("F5"));
fout->WriteLine("非決定係数= " + (1 - r*r).ToString("F5"));
fout->Close();
MessageBox::Show(saveFileDialog1->FileName
+ " was saved.");
Close();
}
===============================================
このプログラムを実行すると図1のウィンドウが表示される。
図1
「button1」ボタンのクリックで入力データ名設定用ダイアログウィンドウが図2のように表示される。
図2
入力データファイル名を指定して「開く」ボタンをクリックすると、計算結果出力用のファイル名設定を求めるダイアログウィンドウが表示される(図3)。
図3
出力はテキストファイルとして書き出されるので、ファイル名の拡張子は「.txt」としておく。出力ファイル名の設定後、「保存」ボタンをクリックすると計算がはじまり、計算終了後図4のメッセージウィンドウが表示される。
図4
メッセージウィンドウの「OK」ボタンのクリックでプログラムが終了する。
入力データは、図5に示すようにスラッシュ/で始まる行の次の行にまず独立変数と従属変数のラベルをこの順に書く。
図5
ラベルを書いた次の行から、独立変数と従属変数の対のデータを1行に一対ずつ書く。データの終了もスラッシュ/で始まる行で示す。すなわち、データはスラッシュで始まる行で挟まれた形で用意する。
図5のファイルを入力データとしたときの出力ファイルは次のようになっている。
============ 出力ファイル例:ここから ====================
Data
file...F:\yasuharu\www\LaCoocan\introprg\SmplRegres\smplregres\smplregres\DataSmplRegres.txt
Data...
変数X
変数Y
x[1]
= 66 y[1]
= 72
x[2]
= 46 y[2]
= 41
x[3] = 87 y[3]
= 93
x[4]
= 82 y[4]
= 82
x[5]
= 42 y[5]
= 41
x[6]
= 72 y[6]
= 64
x[7]
= 31 y[7]
= 27
x[8]
= 69 y[8]
= 68
x[9]
= 84 y[9]
= 79
x[10] =
68
y[10] =
67
x[11] =
50
y[11] =
57
x[12] =
90
y[12] =
90
x[13] =
85
y[13] =
87
x[14] =
29
y[14] =
29
x[15] =
76
y[15] =
75
x[16] =
69
y[16] =
66
x[17] =
84
y[17] =
78
x[18] =
35
y[18] =
31
X==<変数X>
Xの平均 = 64.72222
Xの分散 = 399.86728
Xの標準偏差 = 19.99668
Xの不偏分散 = 423.38889
Xの不偏分散の平方根= 20.57642
Y==<変数Y>
Yの平均 = 63.72222
Yの分散 = 432.97840
Yの標準偏差 = 20.80813
Yの不偏分散 = 458.44771
Yの不偏分散の平方根= 21.41139
共分散 = 408.03395
相関係数=
0.98063
a
= 1.02042
b
= -2.32185
Y(変数Y) = 1.020 * X(変数X) + (-2.322)
決定係数 = 0.96164
非決定係数=
0.03836
============ 出力ファイル例:ここまで========================
プログラム・ファイルは圧縮ファイルsmplregres.zipとしてまとめた。ファイル名smplregres.zipをクリックしてダウンロードしたものをマウスの右ボタンクリックで表示されるメニュ「解凍」あるいは「展開」などを選ぶと解凍できる。解凍したものはVisual C++などで開いてビルド実行することができる。実行形式ファイルsmplregres.exeも用意したので、ファイル名smplregres.exeをクリックしてダウンロード実行することができる。実行形式ファイルは.NET Framework3.5対応である。