隱馬爾科夫和最大熵馬爾科夫 原

隱馬爾科夫實現:

前文鏈接:https://my.oschina.net/u/3268732/blog/1480198

如前文的說法,隱馬爾科夫相關的有兩個式子: 隱馬式子 對兩個式子就可以建立矩陣A,矩陣B。矩陣A是S之間的轉換,爲NN,N爲標籤個數,矩陣中的值爲當前標籤轉移至下一標籤的概率。矩陣B是S與O之間的轉化,爲NM,M爲O的可能狀態,實際上就是在求每個狀態下轉移的概率。模型中還有一個值π,寓意爲每個標籤出現的可能性。

下面對一個解碼問題進行說明:

解碼問題用維特比算法,可應用與文本信息抽取,還有什麼基因檢測,蛋白質二級序列啥的……解碼問題有很多優化,如CRF等,真實工程中就不會用這種原始的了……。對於序列上的每一個元素,其轉換可能爲標籤裏的任意一種,同時,他被下一元素限制,因爲下一元素也是一種轉化的表現。所以大體思路就是先算所有詞的轉化標籤概率(記得考慮自身和上一詞兩種情況),形成一個樹狀結構。(圖示如李航《統計學習方法》P186)這個時候就是遞推,一直推完。然後只需在這所有的路徑裏找到最優的方案,也就是所有概率最優的情況。

第一步:構建一個模型:

這一步直接就是對訓練數據進行統計就完了

第二步:進行維特比算法:

算法:

v1 v2 代碼:

#統計a,pi
def HMMA():
    for i in range(len(label)):
        #初始化計數
        countp=[]
        s=0
        for j in range(len(label)):
            countp.append(0)
        for j in range(trainlen-1):
            if(trainos[j+1]==label[i]):
                s+=1
                countp[label.index(trainos[j])]+=1
        for j in range(len(label)):
            if(s!=0):a[i].append(countp[j]/s)
            else:a[i].append(0)
        #初始初始矩陣
        pi.append(s/trainlen)
    global b
    b=proyx

#統計b
def HMMB():
    count=[]
    for i in range(len(label)):
        countall=0
        for j in range(len(trainx)):
            count.append(0)
        for j in range(trainlen):
            if(trainos[j]==label[i]):
                countall+=1
                count[trainxx.index(trainsq[j])]+=1
        for j in range(len(trainxx)):
            hmmb[i].append(count[j]/countall)
        count=[]

#維特比
def viterbi(testsq,testos,b):
    delta = [[]for i in range(len(testsq))]
    fai = [[]for i in range(len(testsq))]
    #初始化
    if(len(testsq)==0):return
    for i in range(len(label)):
        if(testsq[0])in trainxx:
            delta[0].append(pi[i]*b[i][trainxx.index(testsq[0])]*bigger)
        else:
            delta[0].append(0)
        fai[0].append(0)
    for j in range(1,len(testsq)):
        for i in range(len(label)):
            if(testsq[j]) in trainxx:
                maxtmp=-1
                max_i=0
                for k in range(len(label)):
                    if(delta[j-1][k]*a[i][k]>maxtmp):
                        maxtmp=delta[j-1][k]*a[i][k]
                        max_i=k
                delta[j].append(maxtmp*b[i][trainxx.index(testsq[j])])
                fai[j].append(max_i)
            else:
                delta[j].append(0)
                fai[j].append(0)
    maxtmp=0
    max_i=0
    mytestchoic=[]
    mytestos=[]
    for i in range(len(label)):
        if maxtmp<delta[len(testsq)-1][i]:
            maxtmp=delta[len(testsq)-1][i]
            max_i=i
    mytestchoic.append(max_i)
    for i in range(1,len(testsq)):
        mytestchoic.append(fai[i-1][mytestchoic[i-1]])
    for i in range(len(testsq)):
        mytestos.append(label[mytestchoic[i]])
    print(mytestos)

最大熵隱馬模型:

最大熵的方法就是將隱馬模型中的B這裏的矩陣參數進行優化。另外因爲這個模型又要考慮相近狀態,所以在這裏所有的x相當於當前序列+當前序列標記(xi+yi),y爲前一個標籤狀態(yi-1) 最大熵的就是用來優化似然函數的一種方法,想辦法保證全局最優,期望一個最佳最合理的P(y|x)來預測。 特徵函數f(x,y)(特徵函數,說白了就是一個集合,滿足這一條件的xy就判爲1,否則爲0) memm1 注意:這裏僅僅考慮標籤只有一類的情況,若是多類情況,則需要分別對每一種特徵構造特徵模板,所以多類情況時w也是一個二維數組。最後的p(y|x)應對應隱馬模型中的B 對於似然函數優化: memm2 其中W是可變的,在迭代中會不斷變化他的值,Z(x)表示所有特徵發生的情況下當前x發生的情況(寫程序的時候直接把f()寫成只含0,1的數組不就好了……) 代碼:

#各種統計初始
def definef():
    for i in range(len(label)):
        M.append(trainos.count(label[i]))
        for j in range(len(trainx)):
            f[i].append(0)
            w[i].append(0)
            proyx[i].append(0)
            provx[i].append(0)
    for i in range(trainlen-1):
        f[label.index(trainos[i])][trainx.index(str(trainsq[i+1]+trainos[i+1]))]=1

def countpos():
    #對於每個特徵找各自概率
    for i in range(len(label)):
        countxy=0
        for j in range(trainlen-1):
            if(f[i][trainx.index(trainsq[j+1]+trainos[j+1])]==1 and trainos[j]==label[i]):
                countxy+=1
            provx[i][trainx.index(trainsq[j+1]+trainos[j+1])]+=1
        for j in range(len(trainx)):
            provx[i][j]/=trainlen
        provxy[i]=countxy/trainlen

def countyxpos():
    for i in range(len(label)):
        z=0
        p=[]
        for j in range(len(trainx)):
            p.append(0)
        for j in range(trainlen-1):
            if(trainos[j+1]==label[i]):
                if(f[i][trainx.index(trainsq[j+1]+trainos[j+1])]==1):
                    z+=math.e**(w[i][trainx.index(trainsq[j+1]+trainos[j+1])]*trainx.count(trainsq[j+1]+trainos[j+1]))
            if (f[i][trainx.index(trainsq[j + 1] + trainos[j + 1])] == 1):
                p[trainx.index(trainsq[j+1]+trainos[j+1])]+=w[i][trainx.index(trainsq[j+1]+trainos[j+1])]
        for j in range(len(trainx)):
            if(z!=0):proyx[i][j]=(math.e**p[j])/z
#開始迭代了
def iterate(times):
    for i in range(times):
        for l in range(len(label)):
            for j in range(len(trainx)):
                tmp=0
                if(M[l]!=0 and provx[l][j]*proyx[l][j]*f[l][j]!=0):
                    tmp+=math.log(provxy[l]/provx[l][j]*proyx[l][j]*f[l][j])/M[l]
                global w
                w[l][j]+=tmp
        countyxpos()
        print(i)

注意,儘管一個數據可能序列有多條,輸出一條標籤,這是需要人爲將這些標籤合成成一條標籤。有點狗血……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章