HMM+Viterbi算法分词

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)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,815评论 25 707
  • 20180708星期日 天气晴 天气预报说有中雨,然后改为小雨,最后就下了那么一阵… 今天胥怡戎...
    璇戎爸爸阅读 107评论 0 0
  • 欢迎关注幼儿说,用简书的妈咪,都是有品味的母亲 昨天是年初一,带了阿瓜到亲戚家拜年。本想舒舒服服过个年,但遭遇熊孩...
    幼儿说阅读 1,383评论 4 23
  • 这是我来学校的第三次降温,冷的令我发指!是的,估计也只有我在这个天气裹着厚厚的羽绒服再加一个防风衣了吧。 犹...
    象煦阅读 448评论 2 4