简单的隐马尔可夫模型

来源:互联网 发布:vb的作用与功效副作用 编辑:程序博客网 时间:2024/09/21 11:03

注明:本文是通过阅读学习 ppn029012 博客 机器学习 --- 4. 大内密探HMM(隐马尔可夫)围捕赌场老千 而写的一段简单的推算隐马尔可夫的隐性状态序列的程序。在此感谢 ppn029012!

本文程序用Qt开发环境编写。若代码存在原理性的问题,请帮忙指出。谢谢!代码比较粗糙,若有错误还望指正。

已知条件:条件1.一共三颗骰子,0表示正常骰子,1表示骰子1,2表示骰子2;已知它们之间的关系用状态转移矩阵A表示,A如下:

A = [ 0.15,0.45,0.4;

0.25,0.35,0.4;

    0.10,0.55,0.35;]
条件2.已知每颗骰子掷出某一数字的概率,即已知混淆矩阵B,B如下:
B=[
0.16,0.16,0.16,0.16,0.16,0.16;//骰子0,
0.02,0.02,0.02,0.02,0.02,0.90;//骰子1,最容易掷出6
0.4,0.2,0.25,0.05,0.05,0.05//骰子2,容易掷出小的数
]
条件3.已知初始值为:骰子0.
条件4.已知显性输出为(即投出的骰子的点数,这里共投了19次):
{3,2,1,2,1,1,6,6,6,6,1,6,5,4,3,2,3,5,4}
下面是源代码:

    int dim_hd;//隐性状态维数    int dim_ob;//显性状态维数    int ste_ini;//初始隐性状态    CvMat A;//转移矩阵    CvMat B;//混淆矩阵
    double vals[] = {0.15,0.45,0.4,0.25,0.35,0.4,0.10,0.55,0.35};    double mixs[] = {0.16,0.16,0.16,0.16,0.16,0.16,0.02,0.02,0.02,0.02,0.02,0.90,0.4,0.2,0.25,0.05,0.05,0.05};    A = cvMat(3,3,CV_64FC1,vals);//这个函数是OpenCV里构造矩阵的函数,也可用二维数组构造。构造一个3*3数据类型为64浮点型的矩阵    B = cvMat(3,6,CV_64FC1,mixs);    ste_ini = 0;//刚开始用正常的骰子    ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);   <pre style="margin-top: 0px; margin-bottom: 0px;"><span style=" color:#008000;">    //投掷19次,显性输出为out</span>

   
 //寻找最优隐性序列    dim_ob = 19;    int out[] = {3,2,1,2,1,1,6,6,6,6,1,6,5,4,3,2,3,5,4};//显性输出    double delta[3];//3颗骰子,每一颗都会有一个最大的delta.存储delta    double psi[3][dim_ob];//存储最大delta值时候的j    psi[0][0] = ste_ini;    psi[1][0] = ste_ini;    psi[2][0] = ste_ini;    delta[0] = CV_MAT_ELEM(A,double,ste_ini,0)*CV_MAT_ELEM(B,double,0,out[0]-1);//OpenCV里的函数。获取矩阵中对应位置的值。    delta[1] = CV_MAT_ELEM(A,double,ste_ini,1)*CV_MAT_ELEM(B,double,1,out[0]-1);    delta[2] = CV_MAT_ELEM(A,double,ste_ini,2)*CV_MAT_ELEM(B,double,2,out[0]-1);    ui->tableWidget->setItem(0,0,new QTableWidgetItem(QString::number(delta[0],'g',5).append("(%1)").arg(psi[0][0])) );    ui->tableWidget->setItem(1,0,new QTableWidgetItem(QString::number(delta[1],'g',5).append("(%1)").arg(psi[1][0])) );    ui->tableWidget->setItem(2,0,new QTableWidgetItem(QString::number(delta[2],'g',5).append("(%1)").arg(psi[2][0])) );
    //里面的两个循环用于计算delta的最大值,并记录取得最大值时刻的j的值。
    for(int t=1;t<dim_ob;t++){        //qDebug()<<delta[0]<<delta[1]<<delta[2];        for(int i=0;i<3;i++){            double max = 0;            for(int j=0;j<3;j++){                double temp = delta[j]*CV_MAT_ELEM(A,double,j,i);                max = max > temp ? max : temp;                if(max == temp){                    psi[i][t] = j;                }            }            //qDebug()<<psi[i][t];            delta[i] = CV_MAT_ELEM(B,double,i,out[t]-1)*max;            ui->tableWidget->setItem(i,t,new QTableWidgetItem(QString::number(delta[i],'g',5).append("(%1)").arg(psi[i][t])) );        }    }
    //比较最后时刻的delta值,取delta最大时候的隐性状态作为隐性序列最后一个时刻的值。    double max = 0;    double maxj[dim_ob];// = 0;    for(int j=0;j<3;j++){        max = max > delta[j]?max:delta[j];        if(max == delta[j]){            maxj[dim_ob-1] = j;        }    }
    //然后向前<span style="font-family: Arial, Helvetica, sans-serif;">推导出使该概率最大时候的整个序列。</span>    for(int j=dim_ob-1;j>=1;j--){        int i = maxj[j];        maxj[j-1] = psi[i][j];    }    QString res = "";    for(int i=0;i<dim_ob;i++){        res.append(QString("%1,").arg(maxj[i]));    }    ui->label_2->setText(res);

运行结果:



说明:一共投掷19次,从t=0一直到t=18;在t=18时,最大的delta为delta0,那么隐性序列的最后一个状态为0,即正常骰子,括号内的数字表示前一个隐性状态为0时,会使该时刻的delta最大,然后一直向前推导。红色线即为使t=18时刻delta最大时候的路径.最后结果在下端输出。

0 0
原创粉丝点击