打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【转】Python实现的HMM类

#!/usr/bin/env python

"""
HMM module

This module implements simple Hidden Markov Model class. It follows the description in
Chapter 6 of Jurafsky and Martin (2008) fairly closely, with one exception: in this
implementation, we assume that all states are initial states.

@author: Rob Malouf
@organization: Dept. of Linguistics, San Diego State University
@contact: rmalouf@mail.sdsu.edu
@version: 2
@since: 24-March-2008
"""

from copy import copy

class HMM(object):

    """
    Class for Hidden Markov Models
    An HMM is a weighted FSA which consists of:

        - a set of states (0...C{self.states})
        - an output alphabet (C{self.alphabet})
        - a table of state transition probabilities (C{self.A})
        - a table of symbol emission probabilities (C{self.B})          
        - a list of initial probabilies (C{self.initial})

        We assume that the HMM is complete, and that all states are both initial and final
        states. 
    """
    def __init__(self,states,alphabet,A,B,initial):
        """
        Create a new FSA object
        @param states: states
        @type states: C{list}
        @param alphabet: output alphabet
        @type finals: C{list}
        @param A: transition probabilities
        @type finals: C{list} of C{list}s
        @param B: emission probabilities
        @type finals: C{list} of C{list}s
        @param initial: initial state probabilities
        @type initial: C{list} of C{int}s

        @raise ValueError: the HMM is mis-specified somehow
        """

        # basic configuration
        self.states = states
        self.N = len(self.states)
        self.alphabet = alphabet

        # initial probabilities
        self.initial = initial
        if len(self.initial) != self.N:
            raise ValueError,'only found %d initial probabilities'%len(self.initial)
        if abs(sum(self.initial)-1.0) > 1e-8:
            raise ValueError,'improper initial probabilities'
        # transition probabilities
        self.A = A
        if len(self.A) != self.N:
            raise ValueError,'only found %d transition probability distributions'%len(self.A)
        for i in xrange(self.N):
            if len(self.A[i]) != self.N:
                raise ValueError,'only found %d transition probabilities for state %d'%(len(self.A[i]),i)
            if abs(sum(self.A[i])-1.0) > 1e-8:
                raise ValueError,'improper transition probabilities for state %d'%i

        # emission probabilities       
        self.B = B
        if len(self.B) != self.N:
            raise ValueError,'only found %d emission probability distributions'%len(self.B)
        for i in xrange(self.N):
            if i != self.initial:  # no output from initial state
                if len(self.B[i]) != len(self.alphabet):
                    raise ValueError,'only found %d emission probabilities for state %d'%(len(self.B[i]),i)
                if i != abs(sum(self.B[i])-1.0) > 1e-8:
                    raise ValueError,'improper emission probabilities for state %d'%i

    def allseqs(self,n):
        """Generate all possible state sequences of length n"""

        if n == 0:
            yield [ ]
        else:
            for first in self.states:
                for rest in self.allseqs(n-1):
                    yield [first] + rest

    def prob(self,S,O):
        """Calculate P(O,S|M)"""

        assert len(O) == len(S)
        assert len(O) > 0

        # convert state and output names to indices
        try:
            S = [self.states.index(t) for t in S]
        except ValueError:
            raise ValueError,'unknown state: %s'%t
        try:
            O = [self.alphabet.index(t) for t in O]
        except ValueError:
            raise ValueError,'unknown output: %s'%t

        prob = self.initial[S[0]] * self.B[S[0]][O[0]]
        for t in xrange(1,len(S)):
            prob *= self.A[S[t-1]][S[t]] * self.B[S[t]][O[t]]
        return prob

    def probseq(self,O):
        """Calculate P(O|M) the hard way"""

        # sum probs
        prob = sum(self.prob(S,O) for S in self.allseqs(len(O)))

        return prob

    def forward(self,O):
        """Calculate P(O|M) using the Forward Algorithm"""

        # convert output names to indices
        try:
            O = [self.alphabet.index(t) for t in O]
        except ValueError:
            raise ValueError,'unknown output: %s'%t

        # initialize trellis
        trellis = [ [self.initial[t]*self.B[t][O[0]] for t in xrange(self.N)] ]
        # fill in the rest of the trellis
        for t in xrange(1,len(O)):
            trellis.append([0.0] * self.N)
            for s2 in xrange(self.N):
                for s1 in xrange(self.N):
                    trellis[-1][s2] += self.A[s1][s2] * self.B[s2][O[t]] * trellis[-2][s1]
        # find total probability
        return sum(trellis[-1])

def main():

    ## set up Eisner's HMM

    states = [ 'HOT', 'COLD' ]
    output = [ 1, 2, 3]
    transition = [ [ 0.7, 0.3 ],
                   [ 0.4, 0.6 ] ]            
    emission = [ [ 0.2, 0.4, 0.4 ],
                 [ 0.5, 0.4, 0.1 ] ]
    initial = [ 0.8, 0.2 ]            
    m = HMM(states,output,transition,emission,initial)

    print 'P([HOT,HOT,COLD],[3,1,3]|M) =',
    print m.prob(['HOT','HOT','COLD'],[3,1,3])
    print 'P([3,1,3]|M) =',
    print m.probseq([3,1,3]),'(by the naive method)'
    print 'P([3,1,3]|M) =',
    print m.forward([3,1,3]),'(by the Forward Algorithm)'

main()

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
隐马尔科夫模型HMM自学 (4-1)Forward Algorithm
HMM与分词、词性标注、命名实体识别
Transformers中的Beam Search高效实现
隐马尔可夫模型中的Viterbi算法
【深度】从朴素贝叶斯到维特比算法:详解隐马尔科夫模型
数据科学中的常见的6种概率分布(Python实现)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服