2008. 3.11.
石立 喬
Visual C++ 2008 Express Edition の易しい数値計算(4)
――― ファイルからデータを読み込んで統計処理をする ―――
コンマ区切りのデータをテキストファイルとして格納しておき、これを読み込んで処理をする例を示す。
すでに紹介した文字列の区切り方法と数字(文字列)の数値への変換を使用し、得られた数値を基に、標準偏差と相関係数を求める。結果は、表計算ソフトExcelでの結果と比較する。
新たに使用した統計量
◎不偏分散(unbiased variance)と不偏標準偏差(unbiased standard deviation)
「易しい数値計算(3)」では、分散(σ2)の計算に下記を使用し、標準偏差(σ)は、その平方根であった。ただし、Nは入力したデータの個数であり、xの上にバーが付いたものはxiの平均を意味する。
これ自身、誤りではないが、より多くのデータ(母集団)からN個だけ抜き出されたサンプルデータの場合には、母集団のバラツキを推定するのに、Nの代わりにN-1で割った、より大きい値がが使用される。これによって求まる分散を「不偏分散」(データの個数に依存しない値の意)と呼ぶ。これに対して、Nで割ったものを「標本分散」(限られたサンプルについてのみの値の意)として区別する。同様に、「不偏標
準偏差」と「標本標準偏差」がある。ただし、Nが大きくなると、これらの違いは限りなくゼロになる。表計算ソフトのExcelでは、不偏標準偏差の方が使用されているので、Excelの結果との比較のために、ここではN-1で割る方を使用する。
また、変数として、xやyを使用するので、これらのサフィックスを付加する。下記は、ここで使用する不偏分散の定義であり、数値計算には変形後の式を用いる。この値は負になることはなく、平方根をとって不偏標準偏差σxとすることができる。

◎不偏共分散(unbiased covariance)
xとyとの共分散は、これらのデーが比例的に近いかどうかの目安になる値で、下記で定義される。変形後の式の導出については、各自で確認されたい。この値は、正負の両方をとることがある。次元としては二乗であるが、平方根をとることはないのでσ2のような形ではなく、Sを用いる。

◎相関係数(correlation coefficient)
共分散だけでも、xのデータとyのデータの相対的な関係を知り得るが、それを規準化して−1から1までの間に収めたのが、下記の相関係数である。相関係数では、Nで割ったかN-1で割ったかは関係がなくなる。
データ用ファイルの準備
ここで紹介するプログラムは、ファイルからデータを読み込んで処理をするので、あらかじめデータ用ファイルを作成しておく必要がある。図1は、ここで使用したファイルの内容を確認したもので、1行目にはxのデータが、2行目にはyのデータが、それぞれコンマ区切りで並んでいる。
図1 データ入力のために用意したファイルの内容
プログラム
StreamReaderを使用するために、名前空間System::IOを指定しておく。
xのデータを入れる配列x[]と、yのデータを入れる配列y[]は、それぞれ50個ずつ用意する(実際に使ったのは10個だったが)。
StreamReaderクラスのsreader1にファイル名を与えても、そのファイルが存在しないときはエラーを表示するようにtry〜catch文を使用した。これにより、エラーの場合には、「ファイル’*******’が見つかりませんでした。」と表示される。
ファイルから1行ごとの読み込みは、sreader1->ReadLine()で行う。念のため、読み込んだ結果を表示する。最初の行はxのデータであるので、それをコンマで分割しながら文字列配列sub_string[]に順次入れて行く。これをConvert::ToInt32()で数値に変換しながらxのデータの配列x[]に入れて行く。
ファイルから読み込まれる次の行は、yのデータであるので、同様にy[]に入れて行く。
あとは、標準偏差や相関係数の式にしたがって計算し、表示する。
#include "stdafx.h"
using namespace System;
using namespace System::IO;
int main()
{
Console::Title="相関係数";
array<int>^ x=gcnew array<int>(50);
array<int>^ y=gcnew array<int>(50);
double average_x,average_y;
double stddev_x,stddev_y;
double correl_xy;
int count;
int sum_x=0,sum_y=0,sum_xx=0,sum_yy=0,sum_xy=0;
String^ file_name;
String^ string1;
StreamReader^ sreader1;
array<String^>^ sub_string;
Console::Write("読み込むファイル名を入力して下さい。");
//指定したファイル名でStreamReaderを設定する
file_name=Console::ReadLine();
try{
sreader1=gcnew StreamReader(file_name);
}catch(Exception^ ex){
Console::WriteLine(ex->Message);
return 0;
}
//x[i]の読み込み
string1=sreader1->ReadLine(); //StreamReaderに1行読み込む
Console::WriteLine("Xのデータ:" + string1);
sub_string=string1->Split(','); //コンマで分割する
count=sub_string->Length; //データ個数を取得する
for(int i=0;i<count;i++)
x[i]=Convert::ToInt32(sub_string[i]);
//y[i]の読み込み
string1=sreader1->ReadLine(); //StreamReaderに1行読み込む
Console::WriteLine("Yのデータ:" + string1);
sub_string=string1->Split(','); //コンマで分割する
for(int i=0;i<count;i++)
y[i]=Convert::ToInt32(sub_string[i]);
//統計計算と表示
for(int i=0;i<count;i++){
sum_x+=x[i];
sum_y+=y[i];
sum_xx+=x[i]*x[i];
sum_yy+=y[i]*y[i];
sum_xy+=x[i]*y[i];
}
average_x=(double)sum_x/count;
average_y=(double)sum_y/count;
stddev_x=Math::Sqrt((double)sum_xx/(count-1)-(double)average_x*average_x*count/(count-1));
stddev_y=Math::Sqrt((double)sum_yy/(count-1)-(double)average_y*average_y*count/(count-1));
correl_xy=((double)sum_xy/(count-1)-(double)average_x*average_y*count/(count-1))/(stddev_x*stddev_y);
Console::WriteLine();
string1=String::Format(" Xの平均:{0,5:F2}",average_x);
Console::WriteLine(string1);
string1=String::Format(" Yの平均:{0,5:F2}",average_y);
Console::WriteLine(string1);
string1=String::Format(" Xの標準偏差:{0,10:F7}",stddev_x);
Console::WriteLine(string1);
string1=String::Format(" Yの標準偏差:{0,10:F7}",stddev_y);
Console::WriteLine(string1);
string1=String::Format(" XとYの相関係数:{0,10:F7}",correl_xy);
Console::WriteLine(string1);
Console::ReadLine();
return 0;
}
得られた結果
図3は、ファイルからデータを読み込み、数値計算して得られた結果である。
図2 得られた結果
表計算ソフトExcelによる結果との比較
同様の計算を、表計算ソフトExcel 2003を使って行った結果を図3に示す。体裁を整えるために、「学籍番号」、「英語」、「数学」などと入れてみたが、これに特別な意味はない。
「平均」は=AVERAGE(B2:B11)など、「標準偏差」は=STDEV(B2:B11)など、「相関係数」は=CORREL(B2:B11,C2:C11)を使用した。
上記の計算結果と表計算ソフトの結果とは、良く一致している。これならば、何も「Visual
C++ 2008」でやる必要はないではないか、との声が聞こえてきそうであるが、計算の仕組みの学習と、よりカスタマイズしたソフトの作成への参考になれば幸いである。

図3 Excelによる計算結果