主要內(nèi)容

需要熟悉:UTF-8, GBK編碼使用方式
如果需要使用隱馬爾科夫模型,首先狀態(tài)一定是離散的,觀測值不一定要求是離散的,可以做觀測值是連續(xù)的隱馬爾科夫模型
中文分詞
如下圖:A矩陣是4x4的矩陣(Begin Middle End Single), B矩陣是4x65536的矩陣,π是4個元素的矩陣

用Viterbi算法做文檔的切詞,現(xiàn)在比較常用是直接用jieba組件做分詞
import jieba.posseg
if __name__ == "__main__":
f = open('.\\novel.txt', encoding='utf-8')
str = f.read()#.decode('utf-8')
f.close()
seg = jieba.posseg.cut(str)
for word, pos in seg:
print(word, pos, '|', end=' ')
分詞結(jié)果:

Hmmlearn的安裝
# pip install hmmlearn
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: hmmlearn in c:\python3.6\lib\site-packages (0.2.1)
Requirement already satisfied: numpy in c:\python3.6\lib\site-packages (from hmmlearn) (1.16.2+mkl)
Requirement already satisfied: scikit-learn>=0.16 in c:\python3.6\lib\site-packages (from hmmlearn) (0.20.3)
Requirement already satisfied: scipy>=0.13.3 in c:\python3.6\lib\site-packages (from scikit-learn>=0.16->hmmlearn) (1.0.0)
hmmlearn實現(xiàn)了三種HMM模型類,按照觀測狀態(tài)是連續(xù)狀態(tài)還是離散狀態(tài),可以分為兩類。GaussianHMM和GMMHMM是連續(xù)觀測狀態(tài)的HMM模型,而MultinomialHMM是離散觀測狀態(tài)的模型,也是我們在HMM原理系列篇里面使用的模型。
對于MultinomialHMM的模型,使用比較簡單,"startprob_"參數(shù)對應(yīng)我們的隱藏狀態(tài)初始分布Π, "transmat_"對應(yīng)我們的狀態(tài)轉(zhuǎn)移矩陣A, "emissionprob_"對應(yīng)我們的觀測狀態(tài)概率矩陣B。
對于連續(xù)觀測狀態(tài)的HMM模型,GaussianHMM類假設(shè)觀測狀態(tài)符合高斯分布,而GMMHMM類則假設(shè)觀測狀態(tài)符合混合高斯分布。一般情況下我們使用GaussianHMM即高斯分布的觀測狀態(tài)即可。以下對于連續(xù)觀測狀態(tài)的HMM模型,我們只討論GaussianHMM類。
在GaussianHMM類中,"startprob_"參數(shù)對應(yīng)我們的隱藏狀態(tài)初始分布Π, "transmat_"對應(yīng)我們的狀態(tài)轉(zhuǎn)移矩陣A, 比較特殊的是觀測狀態(tài)概率的表示方法,此時由于觀測狀態(tài)是連續(xù)值,我們無法像MultinomialHMM一樣直接給出矩陣B。而是采用給出各個隱藏狀態(tài)對應(yīng)的觀測狀態(tài)高斯分布的概率密度函數(shù)的參數(shù)。
如果觀測序列是一維的,則觀測狀態(tài)的概率密度函數(shù)是一維的普通高斯分布。如果觀測序列是N維的,則隱藏狀態(tài)對應(yīng)的觀測狀態(tài)的概率密度函數(shù)是N維高斯分布。高斯分布的概率密度函數(shù)參數(shù)可以用μ表示高斯分布的期望向量,Σ表示高斯分布的協(xié)方差矩陣。在GaussianHMM類中,“means”用來表示各個隱藏狀態(tài)對應(yīng)的高斯分布期望向量μ形成的矩陣,而“covars”用來表示各個隱藏狀態(tài)對應(yīng)的高斯分布協(xié)方差矩陣Σ形成的三維張量。
GMHMM

這個例子,給定任何一個樣本點,將其作為高斯分布的采樣,即直接使用隱馬爾科夫模型。從5個高斯分布,隨機選出一個高斯分布,并從中選擇一個樣本來,通過高斯分布,以某種狀態(tài)轉(zhuǎn)移概率矩陣方式,轉(zhuǎn)移到另外的可能的高斯分布上面去。再在這個高斯分布采取一個樣本點,然后繼續(xù)轉(zhuǎn)移。。。不斷做狀態(tài)轉(zhuǎn)移,以及選擇樣本點,只把采樣的狀態(tài)樣本值取出來,這個即是高斯混合模型的樣子。

代碼如下:
# !/usr/bin/python
import numpy as np
from hmmlearn import hmm
import matplotlib.pyplot as plt
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from sklearn.metrics.pairwise import pairwise_distances_argmin
import warnings
def expand(a, b):
return 1.05*a-0.05*b, 1.05*b-0.05*a
if __name__ == "__main__":
warnings.filterwarnings("ignore") # hmmlearn(0.2.0) < sklearn(0.18)
np.random.seed(0)
n = 5 # 隱狀態(tài)數(shù)目
n_samples = 500
pi = np.random.rand(n)
pi /= pi.sum()
print('初始概率:', pi)
A = np.random.rand(n, n)
mask = np.zeros((n, n), dtype=np.bool)
mask[0][1] = mask[0][4] = True
mask[1][0] = mask[1][2] = True
mask[2][1] = mask[2][3] = True
mask[3][2] = mask[3][4] = True
mask[4][0] = mask[4][3] = True
A[mask] = 0
for i in range(n):
A[i] /= A[i].sum()
print('轉(zhuǎn)移概率:\n', A)
means = np.array(((30, 30, 30), (0, 50, 20), (-25, 30, 10), (-15, 0, 25), (15, 0, 40)), dtype=np.float)
# means = np.random.rand(5, 3)
print(means)
for i in range(n):
means[i,:] /= np.sqrt(np.sum(means ** 2, axis=1))[i]
print('均值:\n', means)
covars = np.empty((n, 3, 3))
for i in range(n):
# covars[i] = np.diag(np.random.randint(1, 5, size=2))
covars[i] = np.diag(np.random.rand(3)*0.03+0.001) # np.random.rand ∈[0,1)
print('方差:\n', covars)
model = hmm.GaussianHMM(n_components=n, covariance_type='full')
model.startprob_ = pi
model.transmat_ = A
model.means_ = means
model.covars_ = covars
sample, labels = model.sample(n_samples=n_samples, random_state=0)
# 估計參數(shù)
model = hmm.GaussianHMM(n_components=n, covariance_type='spherical', n_iter=10)
model.fit(sample)
y = model.predict(sample)
np.set_printoptions(suppress=True)
print('##估計初始概率:', model.startprob_)
print('##估計轉(zhuǎn)移概率:\n', model.transmat_)
print('##估計均值:\n', model.means_)
print('##估計方差:\n', model.covars_)
# 類別
order = pairwise_distances_argmin(means, model.means_, metric='euclidean')
print(order)
pi_hat = model.startprob_[order]
A_hat = model.transmat_[order]
A_hat = A_hat[:, order]
means_hat = model.means_[order]
covars_hat = model.covars_[order]
change = np.empty((n, n_samples), dtype=np.bool)
for i in range(n):
change[i] = y == order[i]
for i in range(n):
y[change[i]] = i
print('估計初始概率:', pi_hat)
print('估計轉(zhuǎn)移概率:\n', A_hat)
print('估計均值:\n', means_hat)
print('估計方差:\n', covars_hat)
print(labels)
print(y)
acc = np.mean(labels == y) * 100
print('準確率:%.2f%%' % acc)
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
fig = plt.figure(figsize=(8, 8), facecolor='w')
ax = fig.add_subplot(111, projection='3d')
colors = plt.cm.Spectral(np.linspace(0,1,n))
ax.scatter(sample[:, 0], sample[:, 1], sample[:, 2], s=10, c=labels, cmap=plt.cm.Spectral, marker='o', label='觀測值', depthshade=True)
# plt.plot(sample[:, 0], sample[:, 1], sample[:, 2], lw=0.4, color='#A07070')
colors = plt.cm.Spectral(np.linspace(0, 1, n))
ax.scatter(means[:, 0], means[:, 1], means[:, 2], s=600, c=colors, edgecolor='r', linewidths=1, marker='*', label='中心')
x_min, y_min, z_min = sample.min(axis=0)
x_max, y_max, z_max = sample.max(axis=0)
x_min, x_max = expand(x_min, x_max)
y_min, y_max = expand(y_min, y_max)
z_min, z_max = expand(z_min, z_max)
ax.set_xlim((x_min, x_max))
ax.set_ylim((y_min, y_max))
ax.set_zlim((z_min, z_max))
plt.legend(loc='upper left')
plt.grid(True)
plt.tight_layout(1)
plt.title('GMHMM參數(shù)估計和類別判定', fontsize=18)
plt.show()

問:
問題:π中的M, E概率不是應(yīng)該為0么,取對數(shù)以后應(yīng)該是一一個很大的負數(shù),老師的pi.txt里面好像不是這樣的么?
答:是的,可能代碼有bug