美文网首页
HMM+Viterbi算法分词

HMM+Viterbi算法分词

作者: matrices | 来源:发表于2018-08-21 16:44 被阅读0次

    PS:这篇文章中的代码,仅为一个简单的DEMO,并未进行过代码和算法的优化,参数也未进行过调整,仅仅是演示了一个从训练模型到应用的完整过程

    import numpy as np
    from bidict import bidict
    from functools import reduce
    
    corpus = [
        '小鸟 声音 不大 , 却 句 句 在理 , 全场 都 静静 恭听 。',
        '他 说 : “ 神 是否 创造 世界 ,即 神 对 世界 的 关系 如何 ,这个 问题 其实 就是 关于 精神 对 感性 一般 或 抽象 对 实在、类 对 个体 的 关系 如何 的 问题 ;这个 问题 是 属于 人类 认识 和 哲学 上 最 重要 又 最 困难 的 问题 之一 , 整个 哲学史 其实 只在 这个 问题 周围 绕 圈子 , 古代 哲学 中 斯多葛派 和 伊壁鸠鲁派 间 、 柏拉图派 和 亚里士多德派 间 、 怀疑派 和 独断派 间 的 争论 , 中古哲学 中 唯名论者 和 实在论者 间 的 争论 , 以及 近代 哲学 中 唯心主义者 和 实在论者 或 经验主义者 间 的 争论 , 归根结底 都是 关于 这个 问题 。 ”',
        '讨论 法 的 本位 问题 , 应该 局限 于 实在 法效 用 的 实现 借助 于 何种 规范 手段 的 范围 内 , 它 主要 应 讨论 " 法 是 什么 " 的 问题 , 而 不是 " 法 应当 是 什么 " 的 问题 。',
        '现在 , 你 已是 全班 第一名 了 , 我们 都要 向 你 学习 , 我们 还会 继续 帮助 你 。',
        '他们 的 罪恶 行径 也 从 反面 教育 我们 , 革命 的 政治工作 对于 我们 党 的 各项 工作 , 对于 我们 军队 和 人民 来说 , 确实 是 不可以 须臾 离开 的 生命线 。',
        '从 研究系 办 的 刊物 来看 , 确实 登载 过 大量 的 讨论 社会主义 的 文章 , 似乎 亦 拥护 社会主义 , 但 实际上 这 只是 假象 。',
        '他 那些 舞台 下 、 剧场 外 的 事 的确 是 鲜为人知 的 。', '他 说 的 确实 在理'
    ]
    # 隐序列
    hidden_states = bidict({'B': 0, 'M': 1, 'E': 2, 'S': 3})
    
    atomic = set(reduce(lambda l1, l2: l1 + l2, map(lambda x: list(x), corpus)))
    # 字符及其索引
    characters = bidict(enumerate(atomic))
    
    hidden_states_count = len(hidden_states)
    
    characters_count = len(characters)
    
    #初始概率矩阵
    init_matrix = np.zeros((1, hidden_states_count))
    #转移概率矩阵
    trans_matrix = np.zeros((hidden_states_count, hidden_states_count))
    #输出概率矩阵
    out_matrix = np.zeros((hidden_states_count, characters_count))
    
    for s in corpus:
        words = s.split()
        #初始矩阵
        state = 'B' if len(words[0]) > 1 else 'S'
        init_matrix[0, hidden_states[state]] += 1
        pre = None
        for word in words:
            l = len(word)
    
            #求转移矩阵
            first = 'S' if l == 1 else 'B'
            last = 'S' if l == 1 else 'E'
            if l == 1:
                out_matrix[hidden_states['S'], characters.inv[word[0]]] += 1
            elif l == 2:
                trans_matrix[hidden_states['B'], hidden_states['E']] += 1
                out_matrix[hidden_states['B'], characters.inv[word[0]]] += 1
                out_matrix[hidden_states['E'], characters.inv[word[-1]]] += 1
            else:
                trans_matrix[hidden_states['B'], hidden_states['M']] += 1
                trans_matrix[hidden_states['M'], hidden_states['E']] += 1
    
                out_matrix[hidden_states['B'], characters.inv[word[0]]] += 1
                out_matrix[hidden_states['E'], characters.inv[word[-1]]] += 1
                trans_matrix[hidden_states['M'], hidden_states['M']] += l - 2 - 1
                for i in range(1, l - 1):
                    out_matrix[hidden_states['M'], characters.inv[word[i]]] += 1
            if pre:
                trans_matrix[hidden_states[pre], hidden_states[first]] += 1
            pre = last
    
    #求三个矩阵概率
    init_matrix /= np.sum(init_matrix)
    trans_matrix /= np.sum(trans_matrix)
    out_matrix /= np.sum(out_matrix)
    
    #==========
    input = '他说的确实在理'
    
    ilen = len(input)
    
    path = np.full((hidden_states_count, ilen - 1), -1, dtype=np.int8)
    
    #先求第一个字的概率
    weight = init_matrix * out_matrix[:, characters.inv[input[0]]]
    
    # 求后续概率
    for col in range(1, ilen):
        c = input[col]
        prob = weight.reshape(4,
                              1) * trans_matrix * out_matrix[:, characters.inv[c]]
    
        path[:, col - 1] = np.argmax(prob, axis=0)
        #再取对应的最大概率 赋值给weight
    
        if col == 0:
            print('char', c)
            print("weight:", weight)  #上一个字的可能性权重
            print("weight*trans-martrix", weight.reshape(4, 1) * trans_matrix)
            print("out-matrix", out_matrix[:, characters.inv[c]])
            print("result", prob)
            print("argmax", path[:, col - 1])
            exit()
        weight = np.max(prob, axis=0)
    
    print(path)
    state = 'E' if weight[hidden_states['E']] > weight[hidden_states['S']] else 'S'
    
    
    state_seq = [state]
    for i in range(ilen - 2, -1, -1):
        print(path[hidden_states[state], i])
        state = hidden_states.inv[path[hidden_states[state], i]]
        state_seq.append(state)
    
    state_seq.reverse()
    
    print(state_seq)
    
    result = []
    
    for i, s in enumerate(state_seq):
        result.append(input[i])
        if s in ('S', 'E'):
            result.append(" ")
    
    print(result)
    

    相关文章

      网友评论

          本文标题:HMM+Viterbi算法分词

          本文链接:https://www.haomeiwen.com/subject/giyjiftx.html