常用的分词方法有:
基于规则的分词是通过维护字典的方法,在切分语句时将语句中的字符与词典进行逐一匹配去划分词语,是一种比较机械的分词方式
my_dict = ["江大桥", "研究", "生命科学", "南京市", "研究生", "大桥", "科学", "课题", "南京市长", "生命", "长江大桥", "南京", "市长"]
max_length = max([len(word) for word in my_dict])
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)
# 输出:['南京市长', '江大桥', '研究生', '课题', '是', '研究生', '命', '科学']
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)
# 输出:['南京市', '长江大桥', '研究生', '课题', '是', '研究', '生命科学']
双向匹配是综合正了向匹配和逆向匹配
统计分词是以字为最小单位,相连的字在不同文本中出现的词次越多,说明成词的可能性越大。统计语料中相邻的各个字组合出现的频率,来确定此组字构成词的可靠度。
一段文本通常有多种分隔方式 如:
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