馬爾科夫鏈算法


     這里介紹的馬爾科夫鏈算法實現的功能是:讀入一段英文文本,構造出由這個文本中語言使用情況而形成的統計模型,然后根據統計模型隨機輸出另一段文本。

     馬爾科夫鏈算法的基本思想是:將輸入想象成一些相互重疊的短語構成的序列,把每個短語分割為兩個部分:一部分是由多個詞構成的前綴,另一部分是只包含一個詞的后綴。馬爾科夫鏈算法能夠生成輸出短語的序列,其方法是依據原文本的統計性質,隨機地選擇跟在前綴后面的特定后綴。采用三個詞的短語就能夠很好工作,這三個詞中前兩個詞構成前綴來選擇作為后綴的一個詞 設置:
w1和w2為文本的前兩個詞

輸出w1和w2
循環:
  隨機地選出w3,它是文本中w1w2的后綴中的一個
  打印w3
  把w1和w2分別換成w2和w3
  重復循環

 

選擇二詞前綴,則每個輸出詞w3都是根據它前面的一對詞(w1,w2)得到的。前綴中詞的個數對設計本身並沒有影響,程序應該能對付任意的前綴長度。我們把一個前綴和它所有可能后綴的集合放在一起,稱其為一個狀態。
為了說明問題,假設我們要基於本章開頭的引語里的幾個句子生成一些隨機文本。這里采用
的是兩詞前綴:
Show your flowchars and conceal your tables and I will be mystified. Show your tables and your flowcharts will be obvious. (end)
下面是一些輸入的詞對和跟隨它們之后的詞:
輸入前綴                           跟隨的后綴
Show your                         flowcharts tables
your flowcharts                  and will
flowcharts and                   conceal
flowcharts will                    be
your tables                         and and
will be                               mystified. obvious.
be mystified                       Show
be obvious                         (end)
處理這個文本的馬爾可夫算法將首先打印出 Show   your,然后隨機取出flowcharts或table。如果選中了前者,那么現在前綴就變成 your  flowcharts,而下一個詞應該是and或will。如果它選取 tables,下一個詞就應該是 and。這樣繼續下去,直到產生出足夠多的輸出,或者在找后綴時遇到了結束標志。

C++實現:
#include <iostream>
#include <map>
#include <deque>
#include <vector>
#include <string>
#include <cstdio>
#include <sstream>
#include <ctime>
using namespace std;

enum {
     NPREF  =  2 ,           //前綴的個數
     MAXGEN  =  10000  //最多有那么多個詞
};  

typedef deque<string> Prefix; 
map<Prefix,vector<string> > statetab; // 使用duque 作為第一項方便前綴詞數擴展和改變,這里statetab將前綴和后綴關聯起來

char  NONWORD[] = "\n"; //偽前綴,將真正的輸入作為它的后綴

void add(Prefix &prefix, const string &s)
{
     if(prefix.size() == NPREF) //當前綴數目達到指定詞數之后,改變前綴,也就是w1 w2 變成 w2 w3
     {
          statetab[prefix].push_back(s);
          prefix.pop_front();
     }
     prefix.push_back(s);
}

void build(Prefix &prefix, istream &in)//構造統計表
{
     string buf;
     while(in >> buf)
          add(prefix,buf);
}

void generate(int nwords)
{
     Prefix prefix;
     int i;
     srand(time(NULL));
     for(i = 0; i < NPREF; i++)
          add(prefix,NONWORD);//生成偽前綴
     //cout<<"NOW prefix: "<<prefix[0]<<" "<<prefix[1]<<endl;
     for(i = 0; i < nwords; i++)
     {
          vector<string> & suf = statetab[prefix];
          //cout<<"prefix:"<<prefix[0]<<" suf "<<suf[0]<<endl;
          const string &w = suf[rand() % suf.size()];//在所有可能的后綴中隨機的選擇一個詞
          if(w == NONWORD)
               break;
          cout << w <<" ";
          prefix.pop_front();//改變前綴
          prefix.push_back(w);
     }
     cout<<endl;
}

int main()
{
     int nwords = MAXGEN;
     Prefix prefix;
     string sentence = "Show your flowchars and conceal your tables and I will be mystified. Show your tables and your flowcharts will be obvious. (end)";
     istringstream in(sentence);
     //freopen("mkov.txt","r",stdin);
     for(int i = 0; i < NPREF; i++)
          add(prefix,NONWORD);
     build(prefix,in);
     add(prefix,NONWORD);
     generate(nwords);
     return 0;
}

 

運行結果1:

運行結果2:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM