python 隱馬爾科夫_機器學習算法之——隱馬爾可夫(Hidden Markov ModelsHMM)原理及Python實現...

前言

上星期寫了Kaggle競賽的詳細介紹及入門指導,但對于真正想要玩這個競賽的伙伴,機器學習中的相關算法是必不可少的,即使是你不想獲得名次和獎牌。那么,從本周開始,我將介紹在Kaggle比賽中的最基本的也是運用最廣的機器學習算法,很多項目用這些基本的模型就能解決基礎問題了。

1 概述

隱馬爾可夫模型(Hidden Markov Model,HMM)是結構最簡單的動態貝葉斯網,這是一種著名的有向圖模型,主要用于時序數據建模(語音識別、自然語言處理等)。

假設有三個不同的骰子(6面、4面、8面),每次先從三個骰子里選一個,每個骰子選中的概率為1/3,如下圖所示,重復上述過程,得到一串數字[1 6 3 5 2 7]。這些可觀測變量組成可觀測狀態鏈。

同時,在隱馬爾可夫模型中還有一條由隱變量組成的隱含狀態鏈,在本例中即骰子的序列。比如得到這串數字骰子的序列可能為[D6 D8 D8 D6 D4 D8]。

隱馬爾可夫模型示意圖如下所示:

圖中,箭頭表示變量之間的依賴關系。在任意時刻,觀測變量(骰子點數)僅依賴于狀態變量(哪類骰子),“觀測獨立性假設”。

同時,t時刻的狀態qt僅依賴于t-1時刻的狀態qt-1。這就是馬爾可夫鏈,即系統的下一時刻的狀態僅由當前狀態決定不依賴以往的任何狀態(無記憶性),“齊次馬爾可夫性假設”。

2 隱馬爾可夫模型三要素

對于一個隱馬爾可夫模型,它的所有N個可能的狀態的集合Q={q1,q2,…,qN},所有M個可能的觀測集合V={v1,v2,…,vM}

隱馬爾可夫模型三要素:狀態轉移概率矩陣A,A=[aij]NxN,aij表示任意時刻t狀態qi條件下,下一時刻t+1狀態為qj的概率;

觀測概率矩陣B,B=[bij]NxM,bij表示任意時刻t狀態qi條件下,生成觀測值vj的概率;

初始狀態概率向量Π,Π=(π1,π2,…,πN),πi表示初始時刻t=1,狀態為qi的概率。

一個隱馬爾可夫模型可由λ=(A, B, Π)來指代。

3 隱馬爾可夫模型的三個基本問題(1) 給定模型λ=(A, B, Π),計算其產生觀測序列O={o1,o2,…,oT}的概率P(O|λ);

計算擲出點數163527的概率

(2) 給定模型λ=(A, B, Π)和觀測序列O={o1,o2,…,oT},推斷能夠最大概率產生此觀測序列的狀態序列I={i1,i2,…,iT},即使P(I|O)最大的I;

推斷擲出點數163527的骰子種類

(3) 給定觀測序列O={o1,o2,…,oT},估計模型λ=(A, B, Π)的參數,使P(O|λ)最大;

已知骰子有幾種,不知道骰子的種類,根據多次擲出骰子的結果,反推出骰子的種類

這三個基本問題在現實應用中非常重要,例如根據觀測序列O={o1,o2,…,oT-1,}推測當前時刻最有可能出現的觀測值OT,這就轉換成基本問題(1);

在語音識別中,觀測值為語音信號,隱藏狀態為文字,根據觀測信號推斷最有可能的狀態序列,即基本問題(2);

在大多數應用中,人工指定參數模型已變得越來越不可行,如何根據訓練樣本學得最優參數模型,就是基本問題(3)。

4 三個基本問題的解法

基于兩個條件獨立假設,隱馬爾可夫模型的這三個基本問題均能被高效求解。

4.1 基本問題(1)解法

4.1.1 直接計算法(概念上可行,計算上不可行)

通過列舉所有可能的長度為T的狀態序列I=(i1,i2,…,iT),求各個狀態序列I與觀測序列O同時出現的聯合概率P(I,O|λ),然后對所有可能求和得到P(O|λ)。

狀態序列I=(i1,i2,…,iT)的概率是P(I|λ)=π1a12a23…a(T-1)T

對于固定狀態序列 I,觀測序O=(o1,o2,…,oT)的概率P(O|I,λ)= b11b22…bTT

I 和 O同時出現的聯合概率P(I,O|λ)= P(I|λ) P(O|I,λ)

然后對所有可能的 I 求和,得到P(O|λ)

這種方法計算量很大,算法不可行。

4.1.2 前向算法(forward algorithm)(t=1,一步一步向前計算)

前向概率αt(i)= P(o1,o2,…,ot,ii=qi|λ),表示模型λ,時刻 t,觀測序列為o1,o2,…,ot且狀態為qi的概率。

(1) 初始化前向概率

狀態為qi和觀測值為o1的聯合概率 α1(i)=π1bi1

(2) 遞推t=1,2,…,T-1

根據下圖,得到αt+1(i)= [Σj=1,…,Nαt(j)αji]bi(t+1)

(3) 終止 P(O|λ) = Σi=1,…,NαT(i)

前向算法高效的關鍵是其局部計算前向概率,根據路徑結構,如下圖所示,每次計算直接利用前一時刻計算結果,避免重復計算,減少計算量。

4.1.3 后向算法(backward algorithm)

后向概率βt(i) = P(o1,o2,…,ot,ii=qi|λ),表示模型λ,時刻t,從t+1到時刻T觀測序列o1,o2,…,ot且狀態為qi的概率。

(1)初始化后向概率

對最終時刻的所有狀態為qi規定βT(i) = 1。

(2)遞推t=T-1,T-2,…,1

根據下圖,計算t時刻狀態為qi,且時刻t+1之后的觀測序列為ot+1,ot+2,…,ot的后向概率。只需考慮t+1時刻所有可能的N個狀態qi的轉移概率(transition probability) αij,以及在此狀態下的觀測概率bi(t+1),然后考慮qj之后的后向概率βt+1(j),得到

βt(i) = Σj=1,…,Nβt+1(j)αijbi(t+1).

?(3) 終止 P(O|λ) = Σi=1,…,Nβ1(i)πibi1

前向算法高效的關鍵是其局部計算前向概率,根據路徑結構,如下圖所示,每次計算直接利用前一時刻計算結果,避免重復計算,減少計算量。

4.2 基本問題(2)解法

4.2.1 近似算法

選擇每一時刻最有可能出現的狀態,從而得到一個狀態序列。這個方法計算簡單,但是不能保證整個狀態序列的出現概率最大。因為可能出現轉移概率為0的相鄰狀態。

4.2.2 Viterbi算法

使用動態規劃求解概率最大(最優)路徑。t=1時刻開始,遞推地計算在時刻t狀態為i的各條部分路徑的最大概率,直到計算到時刻T,狀態為i的各條路徑的最大概率,時刻T的最大概率即為最優路徑的概率,最優路徑的節點也同時得到。

如果還不明白,看一下李航《統計學習方法》的186-187頁的例題就能明白算法的原理。

狀態[3 3 3]極為概率最大路徑。

4.3 基本問題(3)解法

4.3.1 監督學習方法

給定S個長度相同的(觀測序列,狀態序列)作為訓練集(O1,I1),O2,I3),…, (Os,Is)使用極大似然估計法來估計模型參數。

轉移概率αij 的估計:樣本中t時刻處于狀態i,t+1時刻轉移到狀態j的頻數為αij,則

觀測概率bij和初始狀態概率πi的估計類似。

4.3.2 Baum-Welch算法

使用EM算法得到模型參數估計式

EM算法是常用的估計參數隱變量的利器,它是一種迭代方法,基本思想是:

(1) 選擇模型參數初始值;

(2) (E步)根據給定的觀測數據和模型參數,求隱變量的期望;

(3) (M步)根據已得隱變量期望和觀測數據,對模型參數做極大似然估計,得到新的模型參數,重復第二步。

5 Python代碼實現

5.1 Baum-Welch算法的程序實現

這里提供Baum-Welch算法的代碼實現。

本來打算試一下用自己寫的HMM跑一下中文分詞,但很可惜,代碼運行的比較慢。所以改成 模擬 三角波 以及 正弦波。

# encoding=utf8

?

import numpy as np

import csv

?

class HMM(object):

def __init__(self,N,M):

self.A = np.zeros((N,N)) # 狀態轉移概率矩陣

self.B = np.zeros((N,M)) # 觀測概率矩陣

self.Pi = np.array([1.0/N]*N) # 初始狀態概率矩陣

?

self.N = N # 可能的狀態數

self.M = M # 可能的觀測數

?

def cal_probality(self, O):

self.T = len(O)

self.O = O

?

self.forward()

return sum(self.alpha[self.T-1])

?

def forward(self):

"""前向算法"""

self.alpha = np.zeros((self.T,self.N))

?

# 公式 10.15

for i in range(self.N):

self.alpha[0][i] = self.Pi[i]*self.B[i][self.O[0]]

?

# 公式10.16

for t in range(1,self.T):

for i in range(self.N):

sum = 0

for j in range(self.N):

sum += self.alpha[t-1][j]*self.A[j][i]

self.alpha[t][i] = sum * self.B[i][self.O[t]]

?

def backward(self):

"""后向算法"""

self.beta = np.zeros((self.T,self.N))

?

# 公式10.19

for i in range(self.N):

self.beta[self.T-1][i] = 1

?

# 公式10.20

for t in range(self.T-2,-1,-1):

for i in range(self.N):

for j in range(self.N):

self.beta[t][i] += self.A[i][j]*self.B[j][self.O[t+1]]*self.beta[t+1][j]

?

def cal_gamma(self, i, t):

"""公式 10.24"""

numerator = self.alpha[t][i]*self.beta[t][i]

denominator = 0

?

for j in range(self.N):

denominator += self.alpha[t][j]*self.beta[t][j]

?

return numerator/denominator

?

def cal_ksi(self, i, j, t):

"""公式 10.26"""

?

numerator = self.alpha[t][i]*self.A[i][j]*self.B[j][self.O[t+1]]*self.beta[t+1][j]

denominator = 0

?

for i in range(self.N):

for j in range(self.N):

denominator += self.alpha[t][i]*self.A[i][j]*self.B[j][self.O[t+1]]*self.beta[t+1][j]

?

return numerator/denominator

?

def init(self):

"""隨機生成 A,B,Pi并保證每行相加等于 1"""

import random

for i in range(self.N):

randomlist = [random.randint(0,100) for t in range(self.N)]

Sum = sum(randomlist)

for j in range(self.N):

self.A[i][j] = randomlist[j]/Sum

?

for i in range(self.N):

randomlist = [random.randint(0,100) for t in range(self.M)]

Sum = sum(randomlist)

for j in range(self.M):

self.B[i][j] = randomlist[j]/Sum

?

def train(self, O, MaxSteps = 100):

self.T = len(O)

self.O = O

?

# 初始化

self.init()

?

step = 0

# 遞推

while step

step+=1

print(step)

tmp_A = np.zeros((self.N,self.N))

tmp_B = np.zeros((self.N,self.M))

tmp_pi = np.array([0.0]*self.N)

?

self.forward()

self.backward()

?

# a_{ij}

for i in range(self.N):

for j in range(self.N):

numerator=0.0

denominator=0.0

for t in range(self.T-1):

numerator += self.cal_ksi(i,j,t)

denominator += self.cal_gamma(i,t)

tmp_A[i][j] = numerator/denominator

?

# b_{jk}

for j in range(self.N):

for k in range(self.M):

numerator = 0.0

denominator = 0.0

for t in range(self.T):

if k == self.O[t]:

numerator += self.cal_gamma(j,t)

denominator += self.cal_gamma(j,t)

tmp_B[j][k] = numerator / denominator

?

# pi_i

for i in range(self.N):

tmp_pi[i] = self.cal_gamma(i,0)

?

self.A = tmp_A

self.B = tmp_B

self.Pi = tmp_pi

?

def generate(self, length):

import random

I = []

?

# start

ran = random.randint(0,1000)/1000.0

i = 0

while self.Pi[i]

ran -= self.Pi[i]

i += 1

I.append(i)

?

# 生成狀態序列

for i in range(1,length):

last = I[-1]

ran = random.randint(0, 1000) / 1000.0

i = 0

while self.A[last][i] < ran or self.A[last][i]<0.0001:

ran -= self.A[last][i]

i += 1

I.append(i)

?

# 生成觀測序列

Y = []

for i in range(length):

k = 0

ran = random.randint(0, 1000) / 1000.0

while self.B[I[i]][k] < ran or self.B[I[i]][k]<0.0001:

ran -= self.B[I[i]][k]

k += 1

Y.append(k)

?

return Y

?

?

?

def triangle(length):

'''三角波'''

X = [i for i in range(length)]

Y = []

?

for x in X:

x = x % 6

if x <= 3:

Y.append(x)

else:

Y.append(6-x)

return X,Y

?

?

?

def show_data(x,y):

import matplotlib.pyplot as plt

plt.plot(x, y, 'g')

plt.show()

?

return y

?

?

if __name__ == '__main__':

hmm = HMM(10,4)

tri_x, tri_y = triangle(20)

?

hmm.train(tri_y)

y = hmm.generate(100)

print(y)

x = [i for i in range(100)]

show_data(x,y)

5.2 運行結果

5.2.1 三角波

三角波比較簡單,我設置N=10,扔進去長度為20的序列,訓練100次,下圖是其生成的長度為100的序列。

可以看出效果還是很不錯的。

5.2.2 正弦波

正弦波有些麻煩,因為觀測序列不能太大,所以我設置N=15,M=100,扔進去長度為40的序列,訓練100次,訓練的非常慢,下圖是其生成的長度為100的序列。

可以看出效果一般,如果改成C的代碼,并增加N應該是能模擬的。

6 HMM的實際應用舉例

參考文獻:

[2]《機器學習》周志華

[3]《統計學習方法》李航

延伸閱讀:

△長按關注「邁微電子研發社」

△長按加入「邁微電子研發社」學習輔導群

給個關注么么噠!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532022.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532022.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532022.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java編程50_java經典50編程題(1-10)

1.有一對兔子從出生后第三個月起&#xff0c;每個月都生一對小兔子&#xff0c;小兔子長到三個月后每個月又生一對兔子&#xff0c;假設兔子不死亡&#xff0c;問每個月兔子的總數為多少&#xff1f;分析過程圖片發自簡書App示例代碼圖片發自簡書App運行結果圖片發自簡書App反思…

python替代hadoop_Python連接Hadoop數據中遇到的各種坑(匯總)

最近準備使用PythonHadoopPandas進行一些深度的分析與機器學習相關工作。(當然隨著學習過程的進展&#xff0c;現在準備使用PythonSparkHadoop這樣一套體系來搭建后續的工作環境)&#xff0c;當然這是后話。但是這項工作首要條件就是將Python與Hadoop進行打通&#xff0c;本來認…

java 自動化測試_java寫一個自動化測試

你模仿購物車試一下&#xff0c;同樣是買東西&#xff0c;加上勝負平的賠率&#xff0c;輸出改下應該就可以了package com.homework.lhh;import java.util.ArrayList;import java.util.Comparator;import java.util.Scanner;public class Ex04 {public static void main(String…

超大規模集成電路_納米級超大規模集成電路芯片低功耗物理設計分析(二)

文 | 大順簡要介紹了功耗的組成&#xff0c;在此基礎上從工藝、電路、門、系統四個層面探討了納米級超大規模集成電路的低功耗物理設計方法。關鍵詞&#xff1a;納米級&#xff1b;超大規模集成電路&#xff1b;電路芯片&#xff1b;電路設計02納米級超大規模集成電路芯片低功耗…

java中的printnb_javaI/O系統筆記

1、File類File類的名字有一定的誤導性&#xff1b;我們可能認為它指代的是文件&#xff0c;實際上卻并非如此。它既能代表一個特定文件的名稱&#xff0c;又能代表一個目錄下的一組文件的名稱。1.1、目錄列表器如果需要查看目錄列表&#xff0c;可以通過file.list(FilenameFilt…

outlook反應慢的原因_保險管怎么區分慢熔和快熔?

保險絲快熔與慢熔的區別所有雙帽;對于這樣的產品特性和安全性熔絲; gG的”&#xff0c;即&#xff0c;與接觸帽組合接觸;即&#xff0c;所述雙(內/外蓋)的蓋。和一般的小型或地下加工廠&#xff0c;以便執行切割角&#xff0c;降低生產成本&#xff0c;這將選擇單個帽鉚接“單&…

java成員內部類_Java中的內部類(二)成員內部類

Java中的成員內部類(實例內部類)&#xff1a;相當于類中的一個成員變量&#xff0c;下面通過一個例子來觀察成員內部類的特點public classOuter {//定義一個實例變量和一個靜態變量private inta;private static intb;//定義一個靜態方法和一個非靜態方法public static voidsay(…

word 通配符_學會Word通配符,可以幫助我們批量處理好多事情

長文檔需要批量修改或刪除某些內容的時候&#xff0c;我們可以利用Word中的通配符來搞定這一切&#xff0c;當然&#xff0c;前提是你必須會使用它。通配符的功能非常強大&#xff0c;能夠隨意組合替換或刪除我們定義的規則內容&#xff0c;下面易老師就分享一些關于查找替換通…

java存儲鍵值結構_java-鍵值存儲為主數據庫

我將要開始一個項目,該項目的讀寫操作非常頻繁且頻繁.因此,環顧四周,我發現內存數據庫正是為此目的而創建的.經過更多調查后,我進入了redis.Redis看起來很酷(雖然剛開始閱讀,但是對此有很多了解).但是我主要只看過關系數據庫,并且以元組和關系的方式來考慮數據(我認為我可以隨著…

python 輸入文件名查找_python 查找文件名包含指定字符串的方法

編寫一個程序&#xff0c;能在當前目錄以及當前目錄的所有子目錄下查找文件名包含指定字符串的文件&#xff0c;并打印出絕對路徑。import osclass searchfile(object):def __init__(self,path.):self._pathpathself.abspathos.path.abspath(self._path) # 默認當前目錄def fin…

java 運行 出現選擇_Eclipse?運行出現java.lang.NoClassDefFoundError的解決方法

上篇博文也提到了這個問題&#xff0c;但沒有深入的講解。這次特意做了整理&#xff0c;詳細解釋其原因。先看錯誤java.lang.NoClassDefFoundError&#xff0c;顯然是java虛擬機找不到指定的類&#xff0c;多數情況下是外部jar中的類。Eclipse的自動化&#xff0c;集成化&#…

設置熄屏_剛買的手機微信收不到信息提醒耽誤事情,手機到手一定要這樣設置...

手機使用過程中經常會遇到第三方軟件接收不到信息提醒的狀況&#xff0c;常常因此耽誤了很多重要的事情&#xff0c;造成損失。特別是剛換新手機或者手機剛升級系統時發生的最多。一般都覺得是手機問題&#xff0c;其實只是手機的系統設置出現了問題&#xff0c;只要跟我按照以…

java判斷對稱素數_SM2非對稱算法的原理及實現 Java SM2的代碼案例 | 一生孤注擲溫柔 | 小奮斗...

SM2橢圓曲線公鑰密碼算法&#xff1a;我國自主知識產權的商用密碼算法&#xff0c;是ECC(Elliptic Curve Cryptosystem)算法的一種&#xff0c;基于橢圓曲線離散對數問題&#xff0c;計算復雜度是指數級&#xff0c;求解難度較大&#xff0c;同等安全程度要求下&#xff0c;橢圓…

multipartfile 獲取音頻時長_抖音音頻下載捷徑:一鍵提取音頻,安卓+ios全通用,完全免費...

本文相關&#xff1a;抖音音頻提取、抖音音頻快捷指令、捷徑怎么獲取抖音音樂…昨天有抖友分享了一個抖音短視頻鏈接&#xff0c;告訴我&#xff0c;她很喜歡這個視頻里的歌曲&#xff0c;但是在很多歌曲app上面卻找不到相同的版本&#xff0c;然后就問我&#xff0c;有沒有什么…

python可以做特效嗎_學習mel語言,Python,JavaScript到什么程度才能做一下大型特效,要自已開發插件腳本呢?...

感謝邀請。首先自己要在某一方面要擅長&#xff0c;認準一個定位。比如android是鑰匙做前端應用軟件的&#xff0c;python可以做爬蟲及其人工智能&#xff0c;js做全段網頁&#xff0c;java主要是做后端的1、我們程序員對于開發軟件來說&#xff0c;無論你選擇的是那種語言&…

POJ2513-Colored Sticks

/*思路&#xff1a;類似圖論中“一筆畫”問題&#xff0c;兩根木棒的相連接的端點是一樣的顏色&#xff0c;&#xff08;a,b&#xff09;--(b,c)--(c, d)....方法&#xff1a;trie樹并查集&#xff0c; 利用trie樹建立字符串和某一個節點的映射&#xff0c;并將這些和字符串構成…

php windows共享內存,給PHP開啟shmop擴展實現共享內存

這篇文章主要介紹了關于給PHP開啟shmop擴展實現共享內存&#xff0c;有著一定的參考價值&#xff0c;現在分享給大家&#xff0c;有需要的朋友可以參考一下在項目開發中&#xff0c;想要實現PHP多個進程之間共享數據的功能&#xff0c;讓客戶端連接能夠共享一個狀態&#xff0c…

導入ansys的實體怎么進行parameter_ANSYS在線纜線束設計中的仿真應用

ANSYS采用ANSYS Maxwell、Q3D、Twin Builder等電磁仿真軟件&#xff0c;從線纜線束設計、寄生參數RLCG提取、到系統電磁兼容提供了全面仿真分析。創建模型ANSYS在Maxwell軟件基礎上提出針對用戶定制化的“線纜線束設計工具包”&#xff0c;幫助客戶參數化建立特定幾何模型&…

怎么做95置信區間圖_這種動態的OD圖怎么做?簡單3步快速搞定

之前在視頻號中發過一個單車的出行數據可視化效果。動態展示了某天單車不同時段的運行情況&#xff0c;這種動態的OD可視化效果是如何制作的呢&#xff1f;使用的是kepler.gl進行制作的&#xff0c;其實非常簡單&#xff0c;3步即可快速搞定。一、數據軟件準備1、軟件制作這種動…

php抖音跳轉地址,PHP如何實現解析抖音無水印視頻

問題來源很多時候你在douyin里看到了一個短視頻&#xff0c;想復制下來自己編輯文字來發布&#xff0c;可是視頻里的水印卻是原者的。這個時候你想把水印去掉&#xff0c;你要如何做呢&#xff1f;這里提供PHP實現去除水印的主要方法&#xff0c;其實很簡單。使用方法&#xff…