·背景javascript
最近乘閒暇之餘初探了HMM(隱馬爾科夫模型),以爲還有點意思,可是網上的教程都超級枯草,可讀性不好,抄來抄去的,一堆公式仍在你面前,誰能搞的懂(但園內的兩篇寫的還算不錯。真才實學)。在熬製3天后,把這篇心得反饋給各位碼友,爲了更加生動的說明模型,特舉例三國殺的"于吉"以便加深各位印象。java
·于吉 ios
武將技:【蠱惑】——你能夠說出任何一種基本牌或非延時類錦囊牌,並正面朝下使用或打出一張手牌。若無人質疑,則該牌按你所述之牌結算。如有人質疑則亮出驗明:若爲真,質疑者各失去1點體力;若爲假,質疑者各摸1張牌。不管真假,棄置被質疑的牌。僅當被質疑的牌爲紅桃花色且爲真時,該牌仍然能夠進行結算。最大的意義在於猜想真假,也就是HMM中的隱藏隊列。算法
·HMM 五對象 ide
·觀察隊列:也就是對手打出的聲明牌序,例如【殺、殺、桃、殺、南蠻】。這3張牌我的感受算是于吉回合內聲明頻率最高的3張牌。函數
·隱藏隊列:也就是對手打出該張牌時是真?是假?,例如【真、真、假、假、真】,這個是HMM以後要計算的對象之一。學習
·初始狀態Matrix P/Pie:聲明第一張牌時,是真是假的機率。spa
·狀態轉移Matrix A:從聲明第二章牌開始,由真變假,或假變真,或真變真,或假變假的機率。3d
·混淆矩陣Matrix B:每次聲明時的真假心態下,該將什麼牌聲明成什麼牌。對象
·HMM 兩大問題(還有一個學習就不寫了)
·評估問題:該輪的聲明牌序,其中存在假牌的可能性有多高?
·解碼問題:該輪的聲明牌序,其中哪幾張牌可能爲假牌?
·HMM 評估算法過程
·HMM 解碼算法過程
·HMM測算結果
Complie Done act:0 Q[0][0]:0.16 Q[0][1]:0.1 act:0 Q[1][0]:0.0332 Q[1][1]:0.047 act:1 Q[2][0]:0.021128 Q[2][1]:0.005476 act:0 Q[3][0]:0.003302 Q[3][1]:0.005047 act:2 Q[4][0]:0.00220564 Q[4][1]:0.00085047 Last Sum Prob=0.00305611 act:0 Q[0][0]:0.16 Q[0][1]:0.1 act:0 com[0]0.096 comp[1]0.07 Q[1][0]:0.0192 com[0]0.064 comp[1]0.03 Q[1][1]:0.032 act:1 com[0]0.01152 comp[1]0.0224 Q[2][0]:0.00896 com[0]0.00768 comp[1]0.0096 Q[2][1]:0.00192 act:0 com[0]0.005376 comp[1]0.001344 Q[3][0]:0.0010752 com[0]0.003584 comp[1]0.000576 Q[3][1]:0.001792 act:2 com[0]0.00064512 comp[1]0.0012544 Q[4][0]:0.00050176 com[0]0.00043008 comp[1]0.0005376 Q[4][1]:0.00016128 Last Max Prob:0.00050176 Path[0][0]=-1 Path[0][1]=-1 Path[1][0]=0 Path[1][1]=0 Path[2][0]=1 Path[2][1]=1 Path[3][0]=0 Path[3][1]=0 Path[4][0]=1 Path[4][1]=1 real 0m0.001s user 0m0.000s sys 0m0.000s
Last Sum Prob=0.00305611,我的理解更貼近於本次序列不做弊的可能性。
Path[i][j]來源t-1時刻兩種隱藏狀態的機率對比,前面<後面 爲1,前面>後面 爲0。從1和0的區別看,0的出現意味着該張牌聲明時做假可能性更高。
·不足之處
·源碼
#include <iostream> #include <vector> #include <map> #include <iomanip> #include <algorithm> using namespace std; vector<string> v_ob; vector<string> v_hide_real; map<string,int> m_ob; map<string,int> m_p; double P[2]={0.8,0.2}; //初始狀態矩陣 double A[2][2]={{0.6,0.4},{0.7,0.3}}; //狀態轉移矩陣 double B[2][3]={{0.2,0.4,0.4},{0.5,0.2,0.3}}; //混淆矩陣 void Para_init(); //初始化觀察隊列 void Forward(); //算前向 void Viterbi(); int main() { Para_init(); Forward(); Viterbi(); } //vector 做爲函數入參數 void show_vector(vector <int> &vecTest) void Viterbi() { int LEN=v_ob.size(); int M=2; double Q[LEN][M]; double Path[LEN][M]; for(int i=0;i<LEN;i++) { int act=m_ob[v_ob[i]]; //當天活動 cout<<"act:"<<act<<"\t"; for(int j=0;j<M;j++) { if(i==0) { Q[i][j]=P[j]*B[j][act]; Path[i][j]=-1; } else { double compare[2]; for(int z=0;z<M;z++) { compare[z]=Q[i-1][z]*A[z][j]; } if(compare[0]<compare[1]) { Path[i][j]=1;} else { Path[i][j]=0;} Q[i][j]=max(compare[0],compare[1])*B[j][act]; cout<<"com[0]"<<left<<setw(11)<<compare[0]<<" "<<"comp[1]"<<setw(11)<<compare[1]<<"\t"; } cout<<"Q["<<i<<"]["<<j<<"]:"<<left<<setw(11)<<Q[i][j]<<"\t"; } cout<<endl; } cout<<endl; cout<<"Last Max Prob:"<<max(Q[LEN-1][0],Q[LEN-1][0])<<endl; cout<<endl; for(int i=0;i<LEN;i++) { for(int j=0;j<M;j++) {cout<<"Path["<<i<<"]["<<j<<"]="<<Path[i][j]<<"\t";} cout<<endl; } } void Forward() { int LEN=v_ob.size(); int M=2; double Q[LEN][M]; for(int i=0;i<LEN;i++) { int act=m_ob[v_ob[i]]; //當天活動 cout<<"act:"<<act<<"\t"; for(int j=0;j<M;j++) { //首行判斷 if(i==0) { Q[i][j]=P[j]*B[j][act]; //cout<<"j="<<j<<"act="<<act<<endl; } else { double sum=0; for(int z=0;z<M;z++) { // cout<<"tmp="<<Q[i-1][z]*A[z][j]<<" "; sum+=Q[i-1][z]*A[z][j]; } Q[i][j]=sum*B[j][act]; } cout<<"Q["<<i<<"]["<<j<<"]:"<<left<<setw(11)<<Q[i][j]<<"\t"; } cout<<endl; } double sum=0; for(int j=0;j<M;j++) { sum+=Q[LEN-1][j]; } cout<<endl; cout<<"Last Sum Prob="<<sum<<endl; cout<<endl; } void Para_init() { //add oberser_list v_ob.push_back("kill"); v_ob.push_back("kill"); v_ob.push_back("tao"); v_ob.push_back("kill"); v_ob.push_back("man"); // dict m_ob.insert(make_pair("kill",0)); m_ob.insert(make_pair("tao",1)); m_ob.insert(make_pair("man",2)); m_p.insert(make_pair("true",0)); m_p.insert(make_pair("false",1)); }
本人才疏學淺,各位麻友輕拍磚~~~ ^_^