【火爐煉AI】機器學習044-創(chuàng)建隱馬爾科夫模型
(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
隱馬爾科夫模型(Hidden Markov Model, HMM)是非常經典的機器學習模型淹仑,在語音識別桩匪,自然語言處理,模式識別等領域中有著非常廣泛的應用雌芽。故而理解和熟練掌握HMM是機器學習領域中一項重要的技能肤舞。
1. 什么是隱馬爾科夫模型
隱馬爾科夫模型是統(tǒng)計模型继榆,用來描述一個含有隱含未知參數(shù)的馬爾科夫過程令哟,其難點是從可觀察參數(shù)確定過程中的隱含參數(shù)跳芳,然后利用這些參數(shù)做進一步的分析。
隱馬爾科夫模型是關于時序的概率模型掏湾,描述一個由隱藏的馬爾科夫鏈隨機生成不可觀測的狀態(tài)隨機序列,再由各個狀態(tài)生成一個可觀測的觀測隨機序列的過程肿嘲。
1.1 馬爾科夫過程
什么是馬爾科夫過程融击?一種無記憶的隨機過程,注意三個時間點:過去雳窟,現(xiàn)在尊浪,將來匣屡,(或者說:昨天,今天拇涤,明天)捣作。在已知現(xiàn)在的狀態(tài)的情況下,將來會處于哪種狀態(tài)只取決于已知的現(xiàn)在狀態(tài)鹅士,而與過去的狀態(tài)無關券躁。即,已知“現(xiàn)在”的狀態(tài)情況下掉盅,“將來”的狀態(tài)和“過去”的狀態(tài)是相互獨立的也拜,這種特性成為馬爾科夫性,具有這種性質的隨機過程叫做馬爾科夫過程趾痘,也稱為馬爾科夫鏈慢哈。
舉個例子:荷花池中一只青蛙在跳動,從一片荷葉跳到下一片上永票。假設青蛙跳過的荷葉編號為X0卵贱,X1,X2,....Xn,且現(xiàn)在青蛙處于Xn這片荷葉上侣集,那么青蛙下一刻要跳到哪片荷葉完全是由現(xiàn)在的荷葉Xn來決定的键俱,而與X0,X1....Xn-1這些荷葉無關。這一過程可以認為是馬爾科夫過程肚吏。
所以馬爾科夫鏈有很強的時間觀念方妖,在t0時刻,青蛙位于X0荷葉上罚攀,t1時刻党觅,青蛙位于X1荷葉上。
1.2 一個鏈條斋泄,兩個序列杯瞻,三個概率
在馬爾科夫模型中,有六個參數(shù)非常重要炫掐,一個鏈條是指一個馬爾科夫過程魁莉,由時間來連接整個鏈條。兩個序列是每個時間點(鏈條上的每個節(jié)點)都具有兩個值募胃,由這兩個值組成的鏈條(或序列):
1)狀態(tài)序列(State Sequence): 由隱藏的馬爾科夫鏈生成的狀態(tài)的序列旗唁,當前處于某種狀態(tài),由這些狀態(tài)組成的序列痹束。
2)觀測序列(Observation Sequence):很多情況下检疫,狀態(tài)并不能完全被我們所看到,我們只能看到某一個狀態(tài)所表現(xiàn)出來的結果祷嘶,這些結果可以被我們觀測到屎媳,故而這些觀測結果所組成的序列就是觀測序列夺溢,它能部分地代表狀態(tài)序列,但是不能完整的展現(xiàn)狀態(tài)序列烛谊。
三個概率是指馬爾科夫鏈往下推動的動力风响,代表這鏈條走勢的方向。
1)初始狀態(tài)概率:表示最開始時刻處于各個狀態(tài)的概率丹禀。
2)狀態(tài)轉移概率:tn時刻的狀態(tài)轉移到下一個tn+1時刻狀態(tài)的概率状勤。
3)觀測概率:如果將馬爾科夫鏈看成一個矩陣,每一行代表每一個時刻湃崩,從上往下都是按照時間來排列的荧降,每一行就代表某一個時刻,也對應于某一個狀態(tài)值攒读,每一列就是這個狀態(tài)下的觀測值朵诫,觀測概率就是在某狀態(tài)下,出現(xiàn)某個觀測值的概率薄扁。
還有兩個基本假設:
1)齊次馬爾科夫假設:隱馬爾科夫鏈在任意時刻T的狀態(tài)值剪返,只依賴于他前一個時刻的狀態(tài)值,而與其他的狀態(tài)值和觀測值無關邓梅,這也是隱馬爾科夫的特點脱盲。
2)觀測獨立性假設:任意時刻的觀測值只依賴于該時刻的狀態(tài),而與其他的觀測值和其他狀態(tài)無關日缨。
有一篇博文講的非常好钱反,有助于對隱馬爾科夫模型的理解,該博文是:一文搞懂HMM(隱馬爾可夫模型)
下面我借用這篇博文中的圖片和例子來說明一下上述幾個關鍵參數(shù)匣距。
1.3 舉例說明
假如有三個不同骰子面哥,如下圖所示,第一個為平時我們所見的正方體型毅待,有六個面尚卫,標號為D6,每擲一次可以得到1-6中的任意一個數(shù)字尸红,每個數(shù)字的概率為1/6.第二個為四面體吱涉,標號為D4,會得到1-4中的任意一個數(shù)字外里,概率為1/4怎爵,第三個為八面體,標號D8盅蝗,會得到1-8中的任意一個數(shù)字鳖链,概率為1/8.
現(xiàn)在我們從這三個骰子中隨機選擇一個,然后每個骰子擲一次风科,得到一個數(shù)字撒轮,一共選10詞,擲10次贼穆。那么我們可能選擇的骰子序列是:D6 D8 D8 D6 D4 D8 D6 D6 D4 D8题山,得到的數(shù)字可能是:1 6 3 5 2 7 3 5 2 4。在每一次時故痊,我們選擇的骰子組成的序列就是狀態(tài)序列顶瞳,如上的(D6 D8 D8 D6 D4 D8 D6 D6 D4 D8),而由該骰子得到的數(shù)字就是我們的觀測值愕秫,組成的就是觀測序列(如數(shù)字1 6 3 5 2 7 3 5 2 4)慨菱。
很明顯,觀測序列是我們可以輕而易舉得到的戴甩,也是很容易觀察到的符喝,故而有時也稱為可見狀態(tài)鏈,而很多時候甜孤,我們不知道選用的是哪個骰子协饲,所以骰子這個狀態(tài)序列就是一個隱藏的序列,也被稱為隱含狀態(tài)鏈缴川。
隱馬爾科夫模型中所說的馬爾科夫鏈其實就是隱含狀態(tài)鏈茉稠。
上面講到的初始狀態(tài)概率就是最開始我們選擇某個骰子的概率,比如此處我們隨機選擇把夸,那么初始狀態(tài)概率就是1/3而线。
狀態(tài)轉移概率就是從一個骰子到下一個骰子的轉換概率,也就是恋日,這一次我們用的是D4骰子膀篮,那么下一次我們應該選擇哪個骰子?此處我們是隨機選擇谚鄙,故而下一個骰子是D4各拷,D6,D8的概率都是1/3闷营,假如我們修改一下規(guī)則烤黍,比如D6后面不能選擇D4,且D6后面再選擇D6的概率是0.9傻盟,D8的概率是0.1速蕊,那么此時的狀態(tài)轉移概率就是(0,0.9,0.1)。由于規(guī)則改變娘赴,故而狀態(tài)轉移概率也發(fā)生改變规哲,得到的就是另外一個全新的HMM。需要注意的是诽表,狀態(tài)轉移概率只存在于狀態(tài)之間的轉移過程中唉锌,而不存在觀測值的改變過程中隅肥。
觀測概率是指,某一個狀態(tài)下得到某個觀測值的概率袄简,這個例子中腥放,加入當前骰子是D6,那么正常情況下,此處我們得到的觀測值是1-6中的任意一個數(shù)字,每個數(shù)字的概率為1/6厂榛,那么此時狀態(tài)的觀測概率就是每個都是1/6。假如有人出老千种柑,對D6骰子動過手腳,比如使得得到1的概率是1/2匹耕,其他數(shù)字(2-6)的概率都是1/10聚请,那么此時的觀測概率也發(fā)生改變,也是一個全新的HMM模型稳其。
用圖表示為:注意圖中的隱含狀態(tài)鏈就是狀態(tài)序列良漱,可見狀態(tài)組成的鏈條就是觀測序列,黑色箭頭表示的從一個隱含狀態(tài)到下一個銀行狀態(tài)的轉換的概率就是狀態(tài)轉移概率欢际,紅色箭頭表示的從一個隱含狀態(tài)到一個觀測值的輸出概率就是觀測概率母市。
對于完全隨機的選擇骰子的過程,那么下一次選擇骰子的概率都是1/3损趋,這種狀態(tài)轉移概率可以表示為:
1.4 算法種類
在真實世界中患久,很多時候我們并不能知道所有的上述五個參數(shù)值,只知道其中的某幾個浑槽,那么這些問題的解決方式也各種各樣蒋失,下面主要講解和HMM模型有關的三類算法,分別解決三種問題桐玻。
1)已知狀態(tài)數(shù)量篙挽,狀態(tài)轉移概率,觀測序列镊靴,求解狀態(tài)序列铣卡。--解碼問題,用維特比算法解決偏竟。
這類問題就是:假如我知道有哪幾種骰子(狀態(tài)數(shù)量)煮落,每種骰子后面應該怎么選擇下一個骰子(狀態(tài)轉移概率),也知道骰子擲出來的結果(觀測序列)踊谋,比如擲出來的一系列結果是(數(shù)字1 6 3 5 2 7 3 5 2 4)蝉仇,那么我們怎么知道每一個步驟都是哪個骰子擲出來的(求解狀態(tài)序列),比如數(shù)字1是D4,D6,D8哪個骰子的的來的轿衔?
這個問題在語音識別領域叫做解碼問題沉迹,有兩種解法,第一種解法是求最大似然狀態(tài)路徑害驹,也就是胚股,求解一串骰子序列,這串骰子序列產生的觀測結果(即得到1 6 3 5 2 7 3 5 2 4這一串數(shù)字)的概率最大裙秋。第二種解法是,求每次擲出的骰子分別是某種骰子的概率缨伊,比如可以求得第一次擲D4的概率是0.5摘刑,D6的概率是0.3,D8的概率是0.2.具體的解法過程請參考其他博文刻坊。
2)已知狀態(tài)數(shù)量枷恕,狀態(tài)轉移概率,觀測序列谭胚,求解得到某個觀測值的概率徐块。 --概率問題,向前向后算法灾而。
這類問題和上面類似胡控,但是這次我們想知道在某一個時刻得到某個數(shù)字的概率。這個問題的求解貌似沒有太多意義旁趟,因為得到的只是某個數(shù)字的概率昼激,而不是真正的這個數(shù)字,但是在賭彩锡搜,股價預測等方面橙困,卻又很大的實用價值,如果在賭彩中知道下一刻某個數(shù)字出現(xiàn)的概率耕餐,或者在股價運行上凡傅,知道下一個交易日出現(xiàn)某個價格的概率,那么我們就能在這個上面賺大把銀子肠缔。
3)已知狀態(tài)數(shù)量夏跷,觀測序列,求解狀態(tài)轉移概率明未。--學習問題拓春,B-W算法。
這是最常見的情況亚隅,很多時候我們只知道有幾個骰子硼莽,并且擲這些骰子得到了很多數(shù)字,那么怎么計算每種骰子后面該怎么選擇下一個骰子了?
關于這些問題的解法懂鸵,請參考博文: 一文搞懂HMM(隱馬爾可夫模型)
2. 創(chuàng)建HMM模型
隱馬爾科夫模型是一個生成模型偏螺,也就意味著一旦掌握了其底層結構,就可以產生數(shù)據(jù)匆光。
2.1. 查看數(shù)據(jù)集序列
本次構建HMM模型的數(shù)據(jù)都存放在data_hmm.txt中套像,首先我們加載這個數(shù)據(jù)集到內存中來。這個數(shù)據(jù)集前兩列是日期终息,第三列是我們所要分析的序列數(shù)據(jù)夺巩。對這列數(shù)據(jù)繪圖可以看出其內在邏輯和結構,如下:
2.2. 構建HMM模型
構建HMM模型的代碼為:
dataset_X=df.iloc[:,2].values.reshape(1,-1).T # 前面兩列是日期周崭,用第2列作數(shù)據(jù)集
# 需要構建成二維數(shù)組形式柳譬,故而需要加上一個軸
print(dataset_X.shape) # 有3312個訓練樣本組成一列
# 建立HMM模型,并訓練
from hmmlearn.hmm import GaussianHMM
model = GaussianHMM(n_components=4, covariance_type="diag", n_iter=1000)
model.fit(dataset_X)
由于此處我們只有一列數(shù)據(jù)续镇,故而需要對這列數(shù)據(jù)準備一下美澳,將其轉變?yōu)槎S數(shù)組,此處得到(3312,1)的二維數(shù)組摸航,每一行就是一個觀測值制跟,構成了一個觀測序列。
這個代碼中用到了hmmlearn模塊酱虎,這個模塊需要自己通過pip install hmmlearn來安裝雨膨。這個模塊實現(xiàn)了三種HMM模型類,按照觀測狀態(tài)是連續(xù)狀態(tài)還是離散狀態(tài)读串,可以分為兩類哥放,GaussianHMM和GMMHMM是連續(xù)觀測狀態(tài)的HMM模型,而MultinomialHMM是離散觀測狀態(tài)的模型
本項目第一爹土,二列代表時間甥雕,且可以看出時間上是連續(xù)的,故而使用GaussianHMM模型胀茵,這個模型假設觀測狀態(tài)符合高斯分布社露,而GMMHMM類則假設觀測狀態(tài)符合混合高斯分布。一般我們使用GaussianHMM即可琼娘。
GuassianHMM的幾個參數(shù):
1峭弟,n_components: 狀態(tài)數(shù)量,默認為1脱拼。
2瞒瘸,covariance_type:有四種: spherical: 在每個狀態(tài)下,觀測值的所有特性分量都使用相同的方差值熄浓,對應協(xié)方差矩陣的非對角為0情臭,對角值相等,即球面特性,這是最簡單的高斯分布PDF俯在。diag: 在每個狀態(tài)下竟秫,觀測值使用對角協(xié)方差矩陣,該矩陣非對角為0跷乐,對角值不相等肥败,是covariance_type的默認參數(shù)。full:在每個狀態(tài)下愕提,觀測值使用完全協(xié)方差矩陣馒稍,里面的元素都為非零。tied: 指所有的狀態(tài)使用相同的完全協(xié)方差矩陣浅侨。這四種PDF類型里面纽谒,spherical, diag和full代表三種不同的高斯分布概率密度函數(shù),而tied則可以看作是GaussianHMM和GMMHMM的特有實現(xiàn)仗颈。其中,full是最強大的椎例,但是需要足夠多的數(shù)據(jù)來做合理的參數(shù)估計挨决;spherical是最簡單的,通常用在數(shù)據(jù)不足或者硬件平臺性能有限的情況之下订歪;而diag則是這兩者一個折中脖祈。在使用的時候,需要根據(jù)可觀察態(tài)向量不同特性的相關性來選擇合適的類型刷晋。
3盖高,n_iter: 最大循環(huán)次數(shù)。
還有一些其他參數(shù)眼虱,但是只有上面三個參數(shù)最重要喻奥,其他可以用默認值即可。
對上面的HMM模型進行訓練之后捏悬,可以查看該模型內部的一些結構和內容撞蚕,比如:計算每一個隱含狀態(tài)的均值和方差:
for i in range(model.n_components): # 打印出每個隱含狀態(tài)
mean=model.means_[i][0]
variance=np.diag(model.covars_[i])[0]
print('Hidden state: {}, Mean={:.3f}, Variance={:.3f}'
.format((i+1),mean,variance))
-------------------------------------輸---------出--------------------------------
Hidden state: 1, Mean=5.092, Variance=0.677
Hidden state: 2, Mean=2.601, Variance=0.257
Hidden state: 3, Mean=8.099, Variance=0.678
Hidden state: 4, Mean=0.600, Variance=0.254
--------------------------------------------完-------------------------------------
2.3. 查看HMM模型的預測效果
HMM模型是生成模型,我們訓練這個模型的最終目的是希望它能夠預測未來某個時點的值过牙,對于這個模型甥厦,我們預測出1000個數(shù)據(jù)點,看看模型的效果如何寇钉。
# 使用HMM模型生成數(shù)據(jù)
N=1000
samples,_=model.sample(N)
plt.plot(samples[:,0])
2.4. 提升HMM模型的性能
上面可以看出刀疙,這個模型生成的數(shù)據(jù)的序列圖和原始的數(shù)據(jù)序列圖相差甚遠,雖然有點起伏波動貌似一致扫倡,但是還難以滿足我們需要谦秧,我們需要的是兩者的相似度越大越好,越大表示HMM模型已經找到了數(shù)據(jù)的變動規(guī)律。
# 模型的提升油够,修改n_components
for i in [8,12,16,18,20]:
model = GaussianHMM(n_components=i, covariance_type="diag", n_iter=1000)
model.fit(dataset_X)
samples,_=model.sample(1000)
plt.plot(samples[:,0])
plt.title('hidden state N={}'.format(i))
plt.show()
運行后會得到五副圖蚁袭,可以看我的源代碼,此處只貼出最后一幅的圖片:
可以看出石咬,隨著隱含狀態(tài)越大揩悄,得到的預測結果圖和原始序列圖的相似度越大,表明HMM模型越準確鬼悠。
########################小**********結###############################
1删性,HMM模型的構建和訓練很簡單,直接使用hmmlearn模塊中的GuassianHMM函數(shù)即可焕窝,其訓練時只需要時序數(shù)據(jù)即可蹬挺。
2,比較難的是理解HMM模型它掂,主要理解隱馬爾科夫鏈巴帮,兩種序列,三種概率虐秋,就能有個大概了解榕茧。
3,HMM模型中GuassianHMM函數(shù)的參數(shù)優(yōu)化空間不大客给,只是優(yōu)化隱含狀態(tài)數(shù)即可用押,從圖中看出,即使隱含狀態(tài)數(shù)比較大得到的結果也不是很理想靶剑,此時需要用深度學習里面的RNN或LSTM來得到準確率更高的模型蜻拨。
#################################################################
注:本部分代碼已經全部上傳到(我的github)上,歡迎下載桩引。
參考資料:
1, Python機器學習經典實例缎讼,Prateek Joshi著,陶俊杰坑匠,陳小莉譯