相関係数の計算
Javaプログラミング
相関係数を求めるプログラムを作ってみた(リスト1)。ファイル入出力を用いたプログラムはこのウェブサイトの後半に示す。
=================== リスト1(始まり) ===================
package CalcCor;
public class CalcCor {
static
double sqr( double x ){
return
x * x;
}
public
static void main(String args[]){
//
// データの設定
//
double
data[][] = { {1, 5},
{2,
4},
{3,
2},
{5,
1} };
int
n = data.length;
//
// 和を求めて平均を計算する
//
double
sum1 = 0.0, sum2 = 0.0;
for
(int i = 0; i < n; i++){
sum1
+= data[i][0];
sum2
+= data[i][1];
System.out.println("data["
+ i + "][0] = " + data[i][0]
+
" data[" + i +
"][1] = " + data[i][1]);
}
double
mean1 = sum1 / n, mean2 = sum2 / n;
System.out.println("Mean1
= " + mean1 + "
Mean2 = " + mean2);
//
// 2乗和、積和を求めて分散、共分散を計算する
//
double
sum11 = 0.0, sum12 = 0.0, sum22 = 0.0;
for
(int i = 0; i < n; i++){
sum11
+= sqr(data[i][0] - mean1);
sum22
+= sqr(data[i][1] - mean2);
sum12
+= (data[i][0] - mean1) * (data[i][1] - mean2);
}
double
variance1 = sum11 / n, variance2 = sum22 / n;
double
cov = sum12 / n;
//
// 相関係数の計算
//
double
sd1 = Math.sqrt(variance1), sd2 = Math.sqrt(variance2);
double
r = cov / (sd1 * sd2);
System.out.println("Variance1
= " + variance1 + "
Variance2 = " + variance2);
System.out.println("Covariance
= " + cov);
System.out.println("SD1
= " + sd1 + " SD2 =
" + sd2);
System.out.println("r
= " + r);
}
}
=================== リスト1(終わり) ===================
データは、配列宣言
double
data[][] = { {1, 5},
{2,
4},
{3,
2},
{5,
1} };
で設定している。
相関係数は次式
で計算している。詳しくは、<岡本安晴「データ分析のための統計学入門」おうふう>などを参照されたい。
リスト1のプログラムを実行すると、図1のようになる。
図1
他のデータで計算するときは、配列 data[][] をデータに合わせて設定すればよい。
リスト1のプログラムは圧縮ファイルCalcCor.zipとして用意した。圧縮ファイル名CalcCor.zipをクリックしてダウンロード展開すればエディタで開くことが出来る。なお、圧縮ファイル内のソースコードはWindows上で開発されているので、ubuntuなどで使用するときはコード変換が必要である。コード変換については別のウェブサイトで説明している。
データの入力、および計算結果などの出力をファイルによって行う形にリスト1のプログラムを書き換えた。リスト2にファイル入出力を用いたプログラムを示す。
===================== リスト2(始まり) ==========================
package CalcCorF;
import java.io.*;
import ExtractSubString.*; // 区切り文字で区切られた部分文字列の取り出し用パッケージ
import CalcStats.*; // 相関係数などを算出するためのクラス型 CalcStats が定義されている
public class CalcCorF {
static
double sqr( double x ){
return
x * x;
}
public
static void main(String args[]){
try{
//
// キーボード入力をバッファー付きで設定
//
BufferedReader
cin = new BufferedReader( new InputStreamReader(System.in) );
System.out.print("Input
Data File = ");
//
// 入力データファイルの設定
//
String
fin_nm = cin.readLine();
BufferedReader
fin = new BufferedReader( new FileReader(fin_nm));
//
// 出力用テキストファイルの設定
//
System.out.print("Output
File Name = ");
String
fout_nm = cin.readLine();
PrintWriter
fout = new PrintWriter( new BufferedWriter( new FileWriter(fout_nm)));
double
data[][] = new double[1000][2];
ExtractSubString
Extrct = new ExtractSubString(); // 部分文字列取り出し用オブジェクト
char
ck_c[] = { ' ', '\t', '\n', ',', '\f', '\r' }; // 区切り文字の選択
Extrct.ck_list
= ck_c; // 区切り文字のオブジェクトへの設定
int
n = 0;
while(true){
String
s = fin.readLine();
if(s.length()
> 0)
if
(s.charAt(0) == '/') // スラッシュ / で始まる行まで読み進む
break;
}
while(true){
String
s = fin.readLine();
if
(s.charAt(0) == '/') break; // スラッシュ / で始まる行で読み込みの終了
Extrct.CheckStr(s); // s
に読み込んだ文字列をE xtrct に設定
data[n][0]
= Double.parseDouble(Extrct.getStrR(0)); // 1
番目のデータの取り出し。最初のデータは
0 番目の数える
data[n][1]
= Double.parseDouble(Extrct.getStrR(1)); // 2
番目のデータの取り出し
n++;
}
fin.close();
fout.println("Data...");
for
(int i = 0; i < n; i++){
//
// 読み込んだデータの確認用出力
//
System.out.println("data["
+ i + "][0] = " + data[i][0]
+
" data[" + i +
"][1] = " + data[i][1]);
fout.println("data["
+ i + "][0] = " + data[i][0]
+
" data[" + i +
"][1] = " + data[i][1]);
}
fout.println();
//
// 相関係数などの計算のためのクラス型 CalcStats のオブジェクト calc
//
CalcStats
calc = new CalcStats( data, n );
calc.calc(); // 相関係数などの統計量の計算
String
fs = String.format("mean0 = %-9.5f mean1 = %-9.5f",
calc.mean0, calc.mean1);
fout.println(fs);
fs
= String.format("var0 = %-9.5f var1 = %-9.5f",
calc.variance0, calc.variance1);
fout.println(fs);
fs
= String.format("SD0 = %-9.5f
SD1 = %-9.5f", calc.sd0, calc.sd1);
fout.println(fs);
fs
= String.format("Covarinace = %-9.5f", calc.cov);
fout.println(fs);
fs
= String.format("r = %-9.5f", calc.r);
fout.println(fs);
fout.close();
}
catch(Exception
e){
System.out.println("Exception..."
+ e);
System.exit(1);
}
}
}
===================== リスト2(終わり) ==========================
キーボードからの入力用ストリームとして cin を以下のように設定して、入力用データファイル名の読み込みを要求している。
BufferedReader cin = new BufferedReader( new InputStreamReader(System.in) );
System.out.print("Input Data File = ");
入力用ファイル名を読み込み、ファイル入力のストリーム fin を以下のように設定している。
String fin_nm = cin.readLine();
BufferedReader fin = new BufferedReader( new FileReader(fin_nm));
入力ファイルは図2に示す形式で用意する。
図2
先頭がスラッシュ / で始まる行(図2では2行目)の次の行からデータを1対ずつ書いていく。データの最後の行の次の行(7行目)はスラッシュ / で始め、データの終わりであることを示す。
出力用ファイルもファイル名の入力とファイル出力のストリーム fout の設定を以下のように行っている。
System.out.print("Output File Name = ");
String fout_nm = cin.readLine();
PrintWriter fout = new PrintWriter( new BufferedWriter( new FileWriter(fout_nm)));
データの読み込みは行単位で行っているが、読み込んだ行から必要なデータ値を取り出すためにクラス型ExtractSubString (パッケージExtractSubString)のオブジェクト Extrct を用意している。
ExtractSubString Extrct = new ExtractSubString(); // 部分文字列取り出し用オブジェクト
char ck_c[] = { ' ', '\t', '\n', ',', '\f', '\r' }; // 区切り文字の選択
Extrct.ck_list = ck_c; // 区切り文字の設定
データの読み込みは、まず最初のスラッシュ / で始まる行まで以下のように読み進む。
int n = 0;
while(true){
String s = fin.readLine();
if(s.length() > 0)
if (s.charAt(0) == '/') // スラッシュ / で始まる行まで読み進む
break;
}
次に、スラッシュ / で始まる行まで、データを1行ずつ読み込み、Extrct によって1番目と2番目のデータを取り出し、配列 data に設定している。
while(true){
String s = fin.readLine();
if (s.charAt(0) == '/') break; // スラッシュ / で始まる行で読み込みの終了
Extrct.CheckStr(s); // s に読み込んだ文字列をE xtrct に設定
data[n][0] = Double.parseDouble(Extrct.getStrR(0)); // 1 番目のデータの取り出し。最初のデータは 0 番目の数える
data[n][1] = Double.parseDouble(Extrct.getStrR(1)); // 2 番目のデータの取り出し
n++;
}
fin.close();
データはクラス型 CalcStats (パッケージ CalcStars)のオブジェクト calc によって行っている。
CalcStats calc = new CalcStats( data, n );
calc.calc();
パッケージ CalcStats は、リスト3に示すものである。
===================== リスト3(始まり) ========================
package CalcStats;
public class CalcStats {
double
x[][]; // データ用配列
int
n; // データ数
//
// 算出された統計量格納用フィールド
//
public
double mean0, mean1, variance0, variance1, sd0, sd1;
public
double cov, r;
public
CalcStats(){ x = null; n = 0; }
public
CalcStats( double data[][], int vn ){ x = data; n = vn; }
double
sqr( double v ) { return v * v; }
public
void calc(){
//
// 和を求める
//
double
sum0 = 0.0, sum1 = 0.0;
for
(int i = 0; i < n; i++){
sum0
+= x[i][0];
sum1
+= x[i][1];
}
mean0
= sum0 / n; // 平均値
mean1
= sum1 / n; // 平均値
//
// 2乗和、積和の計算
//
double
sum00 = 0.0, sum01 = 0.0, sum11 = 0.0;
for
(int i = 0; i < n; i++){
sum00
+= sqr(x[i][0] - mean0);
sum01
+= (x[i][0] - mean0) * (x[i][1] - mean1);
sum11
+= sqr(x[i][1] - mean1);
}
variance0
= sum00 / n; // 分散
variance1
= sum11 / n; // 分散
sd0
= Math.sqrt(variance0); // 標準偏差
sd1
= Math.sqrt(variance1); // 標準偏差
cov
= sum01 / n; // 共分散
r
= cov / (sd0 * sd1); // 相関係数
}
}
===================== リスト3(終わり) ======================
プログラムを実行すると、図3のように入力データファイル名を聞いてくる。
図3
入力データファイル名を設定してEnterキーを押すと、次に出力用テキストファイル名の入力が求められる(図4)。
図4
適当なテキストファイル名(ファイル拡張子は「.txt」とするのがよい)を設定してEnterキーを押すと計算が始まる(図5)。
図5
プログラムの実行終了後、出力ファイルを開くと図6のようになっている。
図6
プログラムは圧縮ファイルCalcCorF.zipにまとめた。圧縮ファイル名CalcCorF.zipをクリックしてダウンロード・展開すればエディタ開くことが出来る。プログラム ソース コードは、Windows上で作成されているので、ubuntuなどで開くとコンパイルエラーになる。日本語コードの変換を行うとubuntuで利用できるが、コードの変換については別のウェブサイトで説明している。
なお、散布図の描画機能を付けたJavaFXプログラムは別のウェブサイトで扱っている。