表題の著作の第4章、4.1「概念形成」にかかれているサンプルを、プログラムして計算してみた。
まず、ベイズ定理を用いた計算は、次のようなプログラムだ。g++の一番新しいもので、linuxマシンでコンパイルすればいいと思う。私は、ubuntu 18.04 のg++でコンパイルしている。他のものの場合は、変更が必要になるかもしれない。(なお、その後知ったことだが、これは単純ベイズ分類器 Naive Bayes Classifier というものである。後の記事でもっと詳しく説明するだろう)
#include <iostream> #include <string> #include <cmath> using namespace std; double pxAB(int x[], double pq[]); int main(){ int x[16][4] = { { 0, 0, 0, 0}, //0 { 0, 0, 0, 1}, //1 { 0, 0, 1, 0}, //2 { 0, 0, 1, 1}, //3 { 0, 1, 0, 0}, //4 { 0, 1, 0, 1}, //5 { 0, 1, 1, 0}, //6 { 0, 1, 1, 1}, //7 { 1, 0, 0, 0}, //8 { 1, 0, 0, 1}, //9 { 1, 0, 1, 0}, //10 { 1, 0, 1, 1}, //11 { 1, 1, 0, 0}, //12 { 1, 1, 0, 1}, //13 { 1, 1, 1, 0}, //14 { 1, 1, 1, 1} //15 }; double PA = 0.5; double PB = 0.5; double p[4] = {0.6, 0.8, 0.8, 0.6}; double q[4] = {0.4, 0.2, 0.2, 0.2}; for(int d=0;d<16;d++){ double PxA = pxAB(x[d],p); double PxB = pxAB(x[d],q); double probBx = (PxB*PA)/(PxA*PA+PxB*PB); double probAx = 1-probBx; string AB; if(probAx > probBx) AB = " ==> A"; else AB = " ==> B"; cout << "No." << d << " PAx = " << probAx << " PBx = " << probBx << AB <<endl; } } double pxAB(int x[], double pq[]){ double prob = 1; for(int i=0;i<4;i++){ prob = prob*pow(pq[i],x[i])*pow(1-pq[i],1-x[i]); } return prob; }
以下のように、上記の本に書かれているとおりの結果が出力された。
No.0 PAx = 0.0204082 PBx = 0.979592 ==> B No.1 PAx = 0.111111 PBx = 0.888889 ==> B No.2 PAx = 0.25 PBx = 0.75 ==> B No.3 PAx = 0.666667 PBx = 0.333333 ==> A No.4 PAx = 0.25 PBx = 0.75 ==> B No.5 PAx = 0.666667 PBx = 0.333333 ==> A No.6 PAx = 0.842105 PBx = 0.157895 ==> A No.7 PAx = 0.969697 PBx = 0.030303 ==> A No.8 PAx = 0.0447761 PBx = 0.955224 ==> B No.9 PAx = 0.219512 PBx = 0.780488 ==> B No.10 PAx = 0.428571 PBx = 0.571429 ==> B No.11 PAx = 0.818182 PBx = 0.181818 ==> A No.12 PAx = 0.428571 PBx = 0.571429 ==> B No.13 PAx = 0.818182 PBx = 0.181818 ==> A No.14 PAx = 0.923077 PBx = 0.0769231 ==> A No.15 PAx = 0.986301 PBx = 0.0136986 ==> A
しかし、アソシアトロンのほうがうまく行かない。原因がわかったかたは、ツイッターの @wassiisg まで教えていただきたい。色々テスト、計算過程の検証をしたが、3個のデータについて、ベイズ推定の場合と一致しない。プログラムは、以下のようなものである。
#include <iostream> #include <string> #include <cmath> using namespace std; void estimation(int v[], int data[][4]); int main(){ int data[10][4] = { { 1, 1, 1, 1}, // A { 1, 1, 1, 0}, // A { 1, 1, 0, 1}, // A { 0, 1, 1, 0}, // A { 0, 0, 1, 1}, // A { 1, 0, 0, 0}, // B { 0, 1, 0, 0}, // B { 0, 0, 1, 0}, // B { 1, 0, 0, 1}, // B { 0, 0, 0, 0} // B }; int test[16][4] = { { 0, 0, 0, 0}, //0 B { 0, 0, 0, 1}, //1 NON X { 0, 0, 1, 0}, //2 B { 0, 0, 1, 1}, //3 A { 0, 1, 0, 0}, //4 B { 0, 1, 0, 1}, //5 NON { 0, 1, 1, 0}, //6 A { 0, 1, 1, 1}, //7 B { 1, 0, 0, 0}, //8 B { 1, 0, 0, 1}, //9 NON { 1, 0, 1, 0}, //10 NON X { 1, 0, 1, 1}, //11 NON { 1, 1, 0, 0}, //12 NON X { 1, 1, 0, 1}, //13 A { 1, 1, 1, 0}, //14 A { 1, 1, 1, 1} //15 A }; int M[4][4]; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ M[i][j] = 0; } } for(int d=0;d<10;d++){ for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ int di = data[d][i]; int dj = data[d][j]; if(di == 0) di = -1; if(dj == 0) dj = -1; M[i][j] = M[i][j] + (di*dj); } } } cout << "記憶行列 M " << endl; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ cout << M[i][j] << " "; } cout << endl; } cout << "概念形成 " << endl; for(int d=0;d<16;d++){ cout << "No." << d << ":: "; int v[4]; for(int j=0;j<4;j++) v[j] = 0; for(int i=0;i<4;i++){ for(int k=0;k<4;k++){ int dk = test[d][k]; if(dk == 0) dk = -1; v[i] += M[i][k]*dk; } if(v[i] > 0){ v[i] = 1; cout << "1 "; }else{ v[i] = 0; cout << "0 "; } } estimation(v, data); cout << endl; } return 0; } void estimation(int v[], int data[][4]){ double minidist = 10000; int minino = -1; for(int d=0;d<10;d++){ double dis = 0; for(int j=0;j<4;j++){ // ユークリッドの距離 dis += (double)(data[d][j]-v[j])*(data[d][j]-v[j]); /* // Hamming の距離 if(data[d][j]-v[j] < 0){ dis += v[j]-data[d][j]; }else{ dis += data[d][j]-v[j]; } */ } // ユークリッドの距離 dis = sqrt(dis); // Hamming の距離 //dis = dis/2; if(dis < minidist){ minino = d; minidist = dis; } } if(minino < 5) cout << " ==> A "; else cout << " ==> B "; cout << "( " << minino << ", " << minidist << " )"; }
出力結果は以下のようになる。
記憶行列 M 10 2 -2 4 2 10 2 0 -2 2 10 0 4 0 0 10 概念形成 No.0:: 0 0 0 0 ==> B ( 9, 0 ) No.1:: 0 0 0 1 ==> A ( 4, 1 ) No.2:: 0 0 1 0 ==> B ( 7, 0 ) No.3:: 0 0 1 1 ==> A ( 4, 0 ) No.4:: 0 1 0 0 ==> B ( 6, 0 ) No.5:: 0 1 0 1 ==> A ( 2, 1 ) No.6:: 0 1 1 0 ==> A ( 3, 0 ) No.7:: 0 1 1 1 ==> A ( 0, 1 ) No.8:: 1 0 0 0 ==> B ( 5, 0 ) No.9:: 1 0 0 1 ==> B ( 8, 0 ) No.10:: 1 0 1 0 ==> A ( 1, 1 ) No.11:: 1 0 1 1 ==> A ( 0, 1 ) No.12:: 1 1 0 0 ==> A ( 1, 1 ) No.13:: 1 1 0 1 ==> A ( 2, 0 ) No.14:: 1 1 1 0 ==> A ( 1, 0 ) No.15:: 1 1 1 1 ==> A ( 0, 0 )
ベイズ推定の場合と比べると3つのデータだけ違った結果を出している。