共分散と相関係数
2つの変量、XとY、を座標とする点が、右上がりの直線に沿って、直線の周りに集まって分布しているとき(図1)、平均値を座標とする点より右上にある点の座標値は、いずれも平均値より大きい、 かつ 。また、左下にある点の座標値は、いずれも平均値より小さい、 かつ 。すなわち、であり、である。
右上がりの直線に沿って分布している点は、それぞれの座標値の平均値との差の積が正である
という特徴がある。
図1
逆に、点が右下がりの直線に沿って、直線の周りに集まって、分布しているとき(図2)、平均値を座標とする点より右下にある点の座標値は、平均値からの差の符号が異なる、 かつ 。また、左上にある点の座標値も同様に、平均値からの差の符号が異なる、 かつ 。すなわち、であり、である。
右下がりの直線に沿って分布している点は、それぞれの座標値の平均値との差の積が負である
という特徴がある。
図2
したがって、の符号が全体として正であるか負であるかによって、点の分布が右上がりの直線に沿って分布しているか、あるいは右下がりの直線に沿って分布しているかが表されると考えられる。の平均値は共分散と呼ばれている。共分散は、次式で与えられる。
共分散を求めるプログラム例を以下に示す。
プログラム2.1
#include <iostream>
#include <fstream>
using namespace std;
int main() {
double
x[1000], y[1000];
cout
<< "入力データファイル名 = ";
char
infile[100];
cin
>> infile;
ifstream
fin;
fin.open(infile);
int
n = 0;
double
c;
fin
>> c;
while
(true) {
fin
>> x[n];
if
(x[n] < c) break;
fin
>> y[n];
n++;
}
fin.close();
cout
<< endl << "data..." << endl;
for
(int i = 0; i < n; i++)
cout
<< x[i] << "
" << y[i] << endl;
double
sumx = 0.0, sumy = 0.0;
for
(int i = 0; i < n; i++) {
sumx
+= x[i]; sumy += y[i];
}
double
meanx = sumx / n, meany = sumy / n;
double
sum = 0.0;
for
(int i = 0; i < n; i++)
sum
+= (x[i] - meanx) * (y[i] - meany);
double
cov = sum / n;
cout
<< "共分散
= " << cov << endl;
char
ck;
cin
>> ck;
return
0;
}
プログラム2.1では、データはファイルとして用意する(図3)。図3では、4組のデータ、、、、、がファイルData.txtとして用意されている。データファイルは、プログラムのソースコードファイルと同じフォルダに置いておく。
図3
2行目の「-1」は、基準値として使われている。このデータファイルの最初の値より小さい値が読み込まれたところで、データの読み込みが終了する。図3のデータでは、7行目の「-9」がデータの読み込み終了を示す値である。
プログラム2.1を実行すると、コンソール画面が表示され、入力データファイル名の入力が求められる(図4)。
図4
入力データファイル名を設定する(図5)。
図5
図5は、データファイルData.txtがプログラムソースコードファイルと同じフォルダ(実行時カレントフォルダ)にある場合である。
入力データファイル名を設定して、Enterキーを押すと、次のコード
cin >> infile;
によってファイル名がinfileに読み込まれて、データの読み込みが始まる。データの読み込み後、共分散がコード
double sumx = 0.0, sumy = 0.0;
for (int i = 0; i < n; i++) {
sumx += x[i]; sumy += y[i];
}
double meanx = sumx / n, meany = sumy / n;
double sum = 0.0;
for (int i = 0; i < n; i++)
sum += (x[i] - meanx) * (y[i] - meany);
double cov = sum / n;
cout << "共分散 = " << cov << endl;
によって算出され、表示される(図6)。
図6
図6では、次のコード
char ck;
cin >> ck;
return 0;
によって文字の入力待ちとなっている。何か文字キーを押してEnterキーを押すと
cin >> ck;
の実行終了となり、次の「return 0;」が実行されて、プログラムの実行終了となる。
共分散の値は、点の分布の相似変換によって値が変わるという特徴がある。データ、、、、、の値を10倍して、、、、、とすると、共分散の値は倍になる。分布の広がりは縦横10倍ずつであるが、分布の形は相似形で同じである。相似変換によって共分散の値は変わるので、共分散の値だけから分布の形状を推測することはできない。分布の形状を表すために、2つの変量の分散をともに1に調整したものが相関係数である。相関係数では、分布の広がりが常に分散が1であるように調整されているので、相関係数の値から2つの変数がどの程度直線的関係にあるかが推測できる。相関係数は次式で与えられる。
分母の値によって、それぞれの分散が1の場合に調整されている。
相関係数を求めるプログラム例を以下に示す。
プログラム2.1
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
inline double sqr(double v) {
return
v * v;
}
int main() {
double
x[1000], y[1000];
cout
<< "入力データファイル名 = ";
char
infile[100];
cin
>> infile;
ifstream
fin;
fin.open(infile);
int
n = 0;
while
(!fin.fail()) {
fin
>> x[n];
// 読み込みデータがないとき、fin.fail() は true になる。
if
(fin.fail()) break;
fin
>> y[n];
n++;
}
cout
<< endl << "data..." << endl;
for
(int i = 0; i < n; i++)
cout
<< x[i] << "
" << y[i] << endl;
double
sumx = 0.0, sumy = 0.0;
for
(int i = 0; i < n; i++) {
sumx
+= x[i]; sumy += y[i];
}
double
meanx = sumx / n, meany = sumy / n;
double
sumxy = 0.0, sumxx = 0.0, sumyy = 0.0;
for
(int i = 0; i < n; i++) {
sumxy
+= (x[i] - meanx) * (y[i] - meany);
sumxx
+= sqr(x[i] - meanx);
sumyy
+= sqr(y[i] - meany);
}
double
r = sumxy / sqrt(sumxx * sumyy);
cout
<< "相関係数
= " << r << endl;
char
ck;
cin
>> ck;
return
0;
}
入力データファイルの例を図7に示す。
図7
図7のファイルの場合、図3のファイルと異なり、読み込みの基準値がない。これは、プログラム2.1では、次のコードによって
fin >> x[n]; // 読み込みデータがないとき、fin.fail() は true になる。
if (fin.fail()) break;
読み込みデータが無くなったときにwhile文を抜け出すようになっているからである。
プログラムの使い方は、プログラム2.1の場合と同様である。
プログラムを実行すると図8のように入力データファイル名の設定が求められる。
図8
入力データファイル名を設定する(図9)。
図9
ファイル名の設定後、Enterキーを押すと、データが読み込まれて計算が行われ、相関係数が表示される(図10)。
図10
何か文字キーを押してEnterキーを押すと、プログラムの終了となる。