自定义中文分词

て烟熏妆下的殇ゞ 提交于 2020-03-08 13:28:55

分词

常用的分词方法有:

  • 基于规则的分词:正向匹配、逆向匹配、双向匹配
  • 基于统计的分词:基于语言模型、基于序列模型
  • 混合分词:综合多种分词

基于规则的分词

基于规则的分词是通过维护字典的方法,在切分语句时将语句中的字符与词典进行逐一匹配去划分词语,是一种比较机械的分词方式

my_dict = ["江大桥", "研究", "生命科学", "南京市", "研究生", "大桥", "科学", "课题", "南京市长", "生命", "长江大桥", "南京", "市长"]
max_length = max([len(word) for word in my_dict])

前向匹配 MM (maximum match)

def word_cut_mm(sentence):
    """正向匹配"""

    sentence = sentence.strip()
    word_length = len(sentence)
    cut_word_list = []
    while word_length > 0:
        max_cut_length = min(max_length, word_length)
        sub_sentence = sentence[:max_cut_length]
        while max_cut_length > 0:
            if sub_sentence in my_dict or max_cut_length == 1:
                cut_word_list.append(sub_sentence)
                break
            else:
                max_cut_length = max_cut_length - 1
                sub_sentence = sentence[:max_cut_length]
        word_length = word_length - max_cut_length
        sentence = sentence[max_cut_length:]
    return cut_word_list

word = word_cut_mm("南京市长江大桥研究生课题是研究生命科学")
print(word)
# 输出:['南京市长', '江大桥', '研究生', '课题', '是', '研究生', '命', '科学']

后向匹配 RMM (reverse maximum match)

def word_cut_rmm(sentence):
    """逆向最大匹配"""
    cut_word_list = []
    sen_length = len(sentence)
    while sen_length > 0:
        for max_cut_length in range(max_length, 0, -1):
            if sen_length - max_cut_length < 0: continue
            sub_sentence = sentence[(sen_length - max_cut_length):sen_length]
            if sub_sentence in my_dict:
                cut_word_list.append(sub_sentence)
                sen_length -= max_cut_length
                break
            if max_cut_length == 1:
                cut_word_list.append(sub_sentence)
                sen_length -= 1
    return cut_word_list[::-1]    

word = word_cut_rmm("南京市长江大桥研究生课题是研究生命科学")
print(word)
# 输出:['南京市', '长江大桥', '研究生', '课题', '是', '研究', '生命科学']

双向匹配(bi-direction matching )

双向匹配是综合正了向匹配和逆向匹配

  • 如果正向匹配和逆向匹配分词结果不同,则返回词数较少的那个
  • 如果正向匹配和逆向匹配分词词数相同,则返回单字数量较少的那个

基于统计的分词

统计分词是以字为最小单位,相连的字在不同文本中出现的词次越多,说明成词的可能性越大。统计语料中相邻的各个字组合出现的频率,来确定此组字构成词的可靠度。

语言模型分词

  • 输入是一段文本:C=C1,C2,……,Cn
  • 输出是词串:S=W1,W2,……,Wm (其中m<=n)

一段文本通常有多种分隔方式 如:

C:结婚的和尚未结婚
S1:结婚/的/和尚/未/结婚
S2:结婚/的/和/尚未/结婚

求输入C的最大概率切分路径argmax P(S|C)(即要求的S1,S2…Sk的最大值。求最大概率也是求最佳路径的问题,一般采用的是动态规划求最佳路径)

根据贝叶斯公式P(S|C)=P(C|S)*P(S)/P©,则

P(S1|C)=P(C|S1)*P(S1)/P(C)
P(S2|C)=P(C|S2)*P(S2)/P(C)

对于P(S1|C)和P(S2|C)来说,P©是该句子在语料库中出现的概率,是一个定值;P(C|S1)和P(C|S2)为已知切分为S1、S2的情况下句子为C的概率也是定值,为1

因此比较P(S1|C)和P(S2|C)的大小就是比较P(S1)和P(S2)的大小

P(S1|C) = P(S1) =P(W1,W2...Wm1)
P(S2|C) = P(S2) =P(W1,W2...Wm2)

对于一元语言模型:

P(W1,W2...Wm1)≈P(W1).P(W2)...P(Wm1)
在W1,W2...Wm1中,如果某个词不存在,则其概率为零就导致相乘后所有的乘积都为零,一次一般会做 add-one Smoothing操作
W1,W2...Wm1都是大于0小于1的数,当序列比较长时,相乘后可能向下溢出变为0,因此一般会取单调递增 log函数

于是可得:

P(S1) = P(W1,W2...Wm1) = P(W1).P(W2)...P(Wm1)
P(Wi)=Wi在语料库出现的词数/词库中的总数
logP(Wi) = log(Wi在语料库出现的次数/词库中的总词数) = log(Wi在语料库出现的次数)-log(词库中的总词数)=log(freq Wi) - logN
P(S1) = P(W1).P(W2)...P(Wm1)∝logP(W1)+logP(W2)+...+logP(Wm) 
	  = (log(freq W1) - logN).(log(freq W2) - logN)...(log(freq Wm1) - logN)

同理可以求出S2,比较S1和S2的大小,最终获得分词效果

对于二元语言模型

P(W1,W2…Wm1)≈P(W1).P(W2|W1).P(W3|W2)…P(Wm1|Wm-1)∝logP(W1)+logP(W2|W1)+logP(W3|W2)+…+logP(Wm|wM-1)

根据条件概率公式:
P(Wm1|Wm-1) = P(Wm1,Wm-1)/P(Wm-1)
根据大数定律:
P(Wm1,Wm-1) = count(Wm1,Wm-1)/count(*)
P(Wm-1) = count(Wm-1)/count(*) 
于是可得:
P(Wm1|Wm-1) = P(Wm1,Wm-1)/P(Wm-1) =  count(Wm1,Wm-1)/count(Wm-1)
logP(Wm1|Wm-1) = logP(Wm1|Wm-1)= log(count(Wm1,Wm-1)/count(Wm-1)) = log(count(Wm1,Wm-1)) - log(count(Wm-1))

把logP(Wm1|Wm-1)代入logP(W1)+logP(W2|W1)+logP(W3|W2)+…+logP(Wm|wM-1)即可求出S1的概率值

序列模型分词

把分词转换为对句子序列中每个字的标注,根据标注对文本进行分词,最常用的就是HMM和CRF

B:标注要么是一个词的开始
M:一个词的中间位置
E:一个词的结束位置
S:单个字的词


π是初始状态概率向量
A隐含状态转移概率矩阵
B发射概率矩阵
所有的状态序列集合:S = {S1,S2,...,Sn}
所有的观测序列集合:O = {O1,O2,...,Om}
长度为t的状态序列I:I = {i1,i2,...,it}
I对应的观测序列Q:Q = {q1,q2,...,qt}

在模型训练阶段,已知观测序列O={O1,O2,…,Om},使用Baum-Welch算法估计模型λ=πAB的参数(或通过统计的方法获得参数π、A、B),使得P(O|λ)的概率最大

在预测阶段,已知观测序列并利用训练阶段求的的参数λ=πAB,使用Viterbi求给定观测序列条件概率P(I|λO)最大状态序列I

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!