2変量統計量の計算
C++Builderネイティブ・コンソール・アプリケーション
2変量統計量(相関係数、共分散)をそれぞれの変量の1変量統計量(平均、分散、標準偏差)とともに算出するコンソール・アプリケーションを作成した。プログラムのそーす・ファイルなどはまとめて圧縮ファイルCalcStat2Vars.zipとして用意した。ファイル名をクリックしてダウンロードし、マウスの右ボタンクリックで表示されるメニュから「解凍」あるいは「展開」を選ぶと解凍できる。解凍したプログラムをC++Builderで開いて実行すると、コンソール・ウィンドウが開き(図1)、入力データファイル名の設定が求められる。
図1 コンソール・ウィンドウ
C++Builderのコンソールアプリケーションの実行時のcurrent folderはソースファイルなどが格納されているフォルダの1つ下Debugフォルダであるので、データファイルなどがソースファイルと同じフォルダにあるときは、データファイル名の前に「..\」を付けて、1つ上のフォルダであることを示す。例えば、「..\Data.txt」とする。出力ファイルも同じフォルダに置くときは「..\」を付ける。例えば、実行時のコンソールの例(図1)では、出力ファイル名を「..\temp.txt」としている。
テキストファイルは、1行単位で読み込むためのクラス型RdTxtLnをヘッダーファイルmyLib.hに用意して、そのメンバ関数readlineによって行っている。すなわち、入力ファイル名がstring型変数fin_nmに設定されているとき、
RdTxtLn rd( fin_nm );
とクラス型の変数rdを定義することにより、
rd.readline( s );
とstring型変数sを引数として関数readlineを呼び出すと、1行分のデータがsに設定される。クラス型RdTxtLnには、他にファイルを開くメンバ関数open、閉じるための関数closeが用意されている。クラス型RdTxtLnのコードは、このページの最後にmyLib.hのリストを付けておいたので参照されたい。
データは、1行に2変量の値が対で書かれているという形式で用意する(図2)。
図2 データの形式
図2の例では、(1, 5)から(5, 8)までの5組のデータが書かれている。データは、スラッシュ「/」で始まる行の次の行から書かれ、スラッシュ「/」で始まる行で入力データの終わったことが示されるという形式である。
読み込まれた1行分のデータからipos番目のデータを取り出すための関数SeekStrを用意している。関数ヘッダーは
string SeekStr( string s, int ipos );
となっている。取り出されたデータは文字列であるので、これの表わす数値への変換のために関数strToDoubleを用意している。関数ヘッダーは
double strToDouble( string s );
となっている。
これらの関数を用いてプログラムCalcStat2Vars.cppは、直感的に判り易く書かれているが、そのソースコードをヘッダーファイルmyLib.hとソースコードmyLib.cppとともに以下に示す。
========== CalcStat2Vars.cpp ===============
#include <cmath>
#include <iostream>
#include <fstream>
#include "myLib.h"
using namespace std;
using namespace myLib;
#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
//
// 入力用テキストファイル名と入力ストリームの設定
//
cout << "Input data file = ";
string fin_nm;
cin >> fin_nm;
RdTxtLn rd( fin_nm );
if (rd.iCond != 0){
cout << "To open input data file failed." << endl;
return 9;
}
//
// 出力用テキストファイル名と出力ストリームの設定
//
cout << "Output file = ";
char fout_nm[200];
cin >> fout_nm;
ofstream fout( fout_nm );
fout << "Input data file = " << fin_nm << endl << endl;
//
// 入力ファイルの先頭部分("/"で始まる行まで)の読み飛ばし
//
string s;
int ick = 0;
do{
rd.readline( s );
if (s.size() > 0)
if (s[0] == '/') ick = 1;
}while( ick == 0 );
//
// データ数Nを数える
//
int N = 0;
ick = 0;
do {
rd.readline( s );
if (s[0] == '/'){
ick = 1;
} else {
N++;
}
} while (ick == 0);
//
// 入力ファイルの先頭に読み込み位置を戻す
//
rd.close();
rd.open(fin_nm);
if (rd.iCond != 0){
cout << "To re-open the inpur file failed." << endl;
return 9;
}
ick = 0;
do {
rd.readline( s );
if (s.size() > 0)
if (s[0] == '/')
ick = 1;
} while (ick == 0);
double * x, * y;
x = new double[N];
y = new double[N];
for (int i = 0; i < N; i++) {
rd.readline( s );
x[i] = strToDouble(SeekStr(s, 0));
y[i] = strToDouble(SeekStr(s, 1));
}
fout << "\n" << "Data..." << endl;
for (int i = 0; i < N; i++) {
fout << i << ": x = " << x[i] << " \ty = " << y[i] << endl;
}
double sx = 0.0;
double sy = 0.0;
double sxx = 0.0;
double syy = 0.0;
double sxy = 0.0;
for (int i = 0; i < N; i++){
sx += x[i];
sy += y[i];
sxx += sqr(x[i]);
syy += sqr(y[i]);
sxy += x[i] * y[i];
}
double meanX = sx / N;
double meanY = sy / N;
double varX = (sxx / N) - sqr(meanX);
double varY = (syy / N) - sqr(meanY);
double sdX = sqrt(varX);
double sdY = sqrt(varY);
double Cov = (sxy / N) - (meanX * meanY);
double r = Cov / (sdX * sdY);
fout << endl;
fout << "mean of x = " << meanX << endl;
fout << "mean of y = " << meanY << endl;
fout << "Variance of x = " << varX << endl;
fout << "Variance of y = " << varY << endl;
fout << "SD of x = " << sdX << endl;
fout << "SD of y = " << sdY << endl;
fout << "Covarince = " << Cov << endl;
fout << "Correlation = " << r << endl;
double uvarX = N * varX / (N - 1);
double uvarY = N * varY / (N - 1);
double uCov = N * Cov / ( N - 1);
fout << endl;
fout << "Unbiased Var of x = " << uvarX << endl;
fout << "Unbiased Var of y = " << uvarY << endl;
fout << "Unbiased Cov = " << uCov << endl;
fout << "SD(uVarX) = " << sqrt(uvarX) << endl;
fout << "SD(uVarY) = " << sqrt(uvarY) << endl;
rd.close();
fout.close();
delete [] x;
delete [] y;
return 0;
}
===================================
=========== myLib.h ===================
#ifndef MYLIB_CK
#define MYLIB_CK
// 2009.01 Y.Okamoto
#include <iostream>
#include <fstream>
#include <sstream>
namespace myLib {
using namespace std;
//
// x の平方を返す
//
double sqr( double x );
//
// 文字列sの表す整数値を返す
//
int strToInt( string s );
//
// 文字列sの表す実数値を返す
//
double strToDouble( string s );
bool check_c( char c );
//
// 空白で区切られた文字列からなるstring型sに
// 含まれるipos番目の文字列を返す
//
string SeekStr( string s, int ipos );
//
// テキストファイルから1行ごとに読み込むためのクラス型
//
class RdTxtLn {
public:
FILE * fin;
int iCond; // 0: OK, 1: End of File, 9: Open Error, -1: Not initialized
string s;
RdTxtLn(): iCond(-1) {}
//
// nmに読み込み用テキストファイル名を設定
// オープンに成功すればiCondの値は0が設定される。
//
RdTxtLn( string nm ): iCond(0){
fin = fopen( nm.c_str(), "r" );
if (fin == NULL) {
iCond = 9;
return;
} else {
iCond = 0;
return;
}
}
virtual ~RdTxtLn(){
if (iCond == 0) fclose(fin);
}
void open( string nm ){
fin = fopen( nm.c_str(), "r" );
if (fin == NULL) {
iCond = 9;
return;
} else {
iCond = 0;
return;
}
}
void close(){
if (iCond == 0){
fclose(fin);
iCond = -1;
}
}
//
// メソッドreadlineを1回呼び出すと
// ファイルから1行分がstrに読み込まれる
//
int readline( string & str ){
int v = 0;
if (iCond != 0){
v = 1;
return v;
}
const int maxN = 1000;
char c[maxN];
int ipos = 0;
int cv;
while (true){
cv = fgetc(fin);
if (cv == EOF){
c[ipos] = 0;
str = "";
if (ipos > 0)
for (int i = 0; i < ipos; i++)
str += c[i];
iCond = 1;
return v;
}
switch (char(cv)){
case '\r': break;
case '\n': c[ipos] = 0; ipos *= -1; break;
default : c[ipos] = char(cv);
ipos++;
if (ipos > (maxN-2)){
c[maxN-1] = 0;
v = 9;
return v;
}
break;
}
if (ipos <= 0) {
ipos *= -1;
str = "";
if (ipos > 0)
for (int i = 0; i < ipos; i++)
str += c[i];
v = 0;
return 0;
}
}
}
};
} // myLib
#endif
===================================
============= myLib.cpp ================
// 2009.01 Y.Okamoto
#include <iostream>
#include <fstream>
#include <sstream>
#include "myLib.h"
namespace myLib {
using namespace std;
double sqr( double x ){
return x * x;
}
//
// 文字列sの表す整数値を返す
int strToInt( string s ){
istringstream istrm(s);
int i;
istrm >> i;
return i;
}
//
// 文字列sの表す実数値を返す
//
double strToDouble( string s ){
istringstream istrm(s);
double d;
istrm>> d;
return d;
}
bool check_c( char c ){
if ( (c == ' ') || (c == '\t') ){
return true;
} else {
return false;
}
}
//
// 空白で区切られた文字列からなるstring型sに
// 含まれるipos番目の文字列を返す
//
string SeekStr( string s, int ipos ){
string vstr = "";
int sLength = s.size();
if (sLength <= 0){
return vstr;
}
int istart, iend;
if (ipos == 0){
istart = 0;
while( check_c(s[istart]) && (istart < sLength-1) ) istart++;
if (istart == sLength-1){
if (! check_c(s[istart])) vstr += s[istart];
return vstr;
}
// }
iend = istart+1;
while ( (! check_c(s[iend])) && (iend < sLength-1) ) iend++;
if (check_c(s[iend])) iend--;
for (int i = istart; i <= iend; i++)
vstr += s[i];
return vstr;
}
if (ipos > 0){
int istart = 0;
for (int i = 0; i < ipos; i++){
while( check_c(s[istart]) && (istart < sLength-1) ) istart++;
if (istart == sLength-1) return "";
int iend = istart;
while ( (! check_c(s[iend])) && (iend < sLength-1) ) iend++;
if (iend == sLength-1) return "";
istart = iend+1;
}
while( check_c(s[istart]) && (istart < sLength-1) ) istart++;
if (istart == sLength-1)
if (! check_c(s[istart])){
vstr = s[istart];
return vstr;
}else{
return "";
}
iend = istart;
while ( (! check_c(s[iend])) && (iend < sLength-1) ) iend++;
if (check_c(s[iend])) iend--;
for (int i = istart; i <= iend; i++)
vstr += s[i];
return vstr;
}
return vstr;
}
} // mylib
====================================