python实现分词(普通&维特比算法)

11 篇文章 0 订阅

普通方法

思路:

读入词典中的词,每个词对应一个概率;
读入句子,得到所有可能的句子的划分,返回unigram得分最大的一个分割;

其中得到所有可能的分割采用递归的方法,当前词在词典中,就继续递归划分后半段;

概率原理:P(x1,x2,x3,xn)=P(x1)* P(x2)*…*P(xn)
可以转化成-log的加法,返回最小值

代码:

#切割代码
def seg_all(string):
#     string:读入的待分割的句子,递归进行
    def to_seg(string,start,seg):
    #  start是子字符串开始下标 seg是string已经切割部分
        if start >= len(string):
            segments.append(list(seg))
            print("segments_all",segments_all)
            return True
            # 遍历当前位置所有可能的切割
        for i in range(start+1,len(string)+1):
            sub = string[start:i]
    #         print("sub",sub)
            if sub in dic_words:
                seg.append(sub)
                to_seg(string,i,seg)
                seg.pop()

算概率部分就很简单了,dict是已知的,概率也是已知的

    best_segment = []
    best_score = 100
    for seg in segments:
        # TODO ...
        score = 0
        for w in seg:
            if w in word_prob:
                score += -math.log(word_prob[w])
            else: # 不在给定的word_prob
                score += -math.log(0.00001)
        if score < best_score:
            best_score = score
            best_segment = seg
    
    return best_segment     

在这里插入图片描述

维特比算法(viterebi)

思路

1、以词典和输入的句子构建有向图
2、以动态规划的方式求有向图中的最优路径

其中构建有向图:图中的每条边都是合法分隔的概率(可以是log之后),从起点到终点的最短路径就是最优的分割(-log的和)

可以以每个字的概率做最基础的边,本身存在在词典中的词有合适的-log(weight),没有的可以给无穷大;然后考虑从每个字出发的子串是不是合法的词典,若是的话就添加上边,可以用二维数组来表示这个图也可以用邻接矩阵

对有向图求最短路径,可以用动态规划的算法
dp[i]表示到节点i时最短的路径,则:
dp[i] = min{ dp[j]+weight[j][i] }

代码

# 构建图:
    inf = 99999
    graph = [[inf]*len(input_str) for i in range(len(input_str))] # 初始化为二维矩阵
    for s in range(len(input_str)):
        for j in range(s+1,len(input_str)):
            sub = input_str[s:j] # 从s开始的每一个子串
            if sub in dic_words:
                if sub in word_prob:
                    graph[s][j] = -math.log(word_prob[sub])
                else:
                    graph[s][j] = -math.log(0.00001)
    dp = [inf]*len(input_str)
    path = [-1]*len(input_str)
    dp[0] = 0
    for i in range(1,len(input_str)):
        for j in range(i):
            if dp[j]+grapg[j][i] < dp[i]:
                dp[i] = graph[j][i]
                path[i] = j
维特比算法是一种用于隐马尔科夫模型中求解最可能的状态序列的算法。下面是Python实现维特比算法的示例代码: ```python import numpy as np def viterbi(obs, states, start_p, trans_p, emit_p): V = [{}] path = {} for y in states: V[0][y] = start_p[y] * emit_p[y][obs[0]] path[y] = [y] for t in range(1, len(obs)): V.append({}) newpath = {} for y in states: (prob, state) = max((V[t-1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0) for y0 in states) V[t][y] = prob newpath[y] = path[state] + [y] path = newpath (prob, state) = max((V[len(obs) - 1][y], y) for y in states) return (prob, path[state]) # 示例 obs = [0, 1, 2] # 观测序列 states = ['健康', '发烧'] # 隐藏状态 start_p = {'健康': 0.6, '发烧': 0.4} # 初始概率 trans_p = {'健康': {'健康': 0.7, '发烧': 0.3}, '发烧': {'健康': 0.4, '发烧': 0.6}} # 转移概率 emit_p = {'健康': {0: 0.5, 1: 0.4, 2: 0.1}, '发烧': {0: 0.1, 1: 0.3, 2: 0.6}} # 发射概率 prob, path = viterbi(obs, states, start_p, trans_p, emit_p) print("观测序列:", obs) print("最可能的状态序列:", path) print("概率:", prob) ``` 在上面的示例代码中,我们定义了一个`viterbi`函数,它接受观测序列、隐藏状态、初始概率、转移概率和发射概率作为输入,并返回最可能的状态序列和对应的概率。在函数内部,我们使用了一个`V`列表来保存每个时间步骤的最大概率,使用一个`path`字典来保存每个状态的最大概率路径。在计算过程中,我们使用了动态规划的思想,通过递推计算每个时间步骤的最大概率和对应的路径。最后,我们返回最后一个时间步骤的最大概率和对应的状态路径,即为最可能的状态序列。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值