本学期(2018秋季学期)完成了基于最大概率的汉语分词实验,本文为博客第二部分,介绍具体实现过程。实验基于人民日报1998年1月中文语料库,使用Python语言进行中文分词实验。实验实现了FMM、BMM和Bigram算法的分词功能,其中Bigram算法借助前两者分词结果发现歧义,使用Laplace平滑计算最大概率。
1 数据准备
本实验使用人民日报1998年1月中文语料库,经过去除标点符号、词性标注等预处理步骤后共余下19347条。随机取80%作为训练集,余下作为验证集。
2 构建字典
本实验需要构造两个字典,一个用来记录每个字典词出现的词频,另一个用来记录每个词后面出现过那些词(bigram组合)。其中前者使用TrieTree数据结构实现,后者使用Python字典实现。
TrieTree名为字典树、前缀树,用来保存字符串可以提高检索速度。其原理在于,前缀树每一个节点的子节点都拥有相同的前缀。字典树的特点在于每个节点都只含有一个字符,从根节点到某一个节点,路上经过的每个单个字符连起来为该节点对应的字符串。
字典树结构示意图
构建TrieTree字典树的过程如下:
def dict_add(self,word):
'''
add 'word' to self.tree
:param word: the word to be added
:return: nothing; change the self.tree in-place
'''
tree = self.tree
for char in word:
if char in tree:
tree = tree[char]
else:
tree[char] = {}
tree = tree[char]
if "freq" in tree:
tree["freq"] +=1
else:
tree["freq"] =1
得到的字典树结构实例:
{'迈': {'向': {'freq': 1}}, '充': {'满': {'freq': 1}}, '希': {'望': {'freq': 1}}, '的': {'freq': 1}, '新': {'freq': 1, '年': {'freq': 1}}}
判断某词语是否在字典中时,需要递归遍历字典树:
def dict_search(self,word):
'''
search word frequency in the self.tree
:param word:
:return: frequency
'''
tree = self.tree
for char in word:
if char in tree:
tree = tree[char]
else:
return False
if "freq" in tree and tree["freq"] >=1:
return tree["freq"]
else:
return 0
对于记录Bigram组合的词典,其结构如下所示:
{“BEG”:{“你”:3, “今天”:2}, “你”:{“好”:6}}
3 FMM和BMM
正向最大匹配算法(FMM)是一种基于词典的分词方法。对于每个句子从左到右扫描寻找词的最大匹配,在这里限定匹配词语最大长度为4。而BMM算法则是从句子后往前遍历,仅仅是方向相反。
FMM匹配过程如下:
def fmm(self,sent):
thedict = self.tree
MAXLEN = self.MAXLEN
sent = sent.strip()
ans = []
while len(sent):
for i in range(min(len(sent), MAXLEN), 0, -1):
tomatch = sent[:i]
if self.dict_search(tomatch):
ans.append(tomatch)
sent = sent[i:]
break
elif len(sent[:i]) == 1:
ans.append(tomatch)
sent = sent[i:]
return ans
4 Bigram模型
通常情况下,FMM或BMM可以得到正确的分词结果。但对于少部分歧义语句,需要借助概率判断采用哪种分词方案。例如,"你有意见分歧上报"在BMM算法中会被切割成"你/有/意见/分歧/上报",而在FMM算法下则会切割成"你/有意/见/上报".
自然语言可看作一个马氏链模型,可根据前面的词预测后面出现的词语.依据训练语料中单个词汇出现的频率以及词语两两组合出现的次数(Bigram),我们可以通过概率进行比较.
对于:
C = "有意见分歧"
C1: 有/ 意见/ 分歧/
C2: 有意/ 见/ 分歧/
有贝叶斯公式:
而一个词的概率可以用其出现次数除以预料中总次数得到.
计算概率时,如果词语不在字典中,会使得概率为0的情况.为避免0值,这里采用拉普拉斯平滑算法,将词语出现频数设为1.
如果FMM和BMM算法的切分结果相同,说明没有歧义,直接采用其切分结果即可;如果FMM和BMM算法切分结果不同,说明该语句含有歧义。对比FMM和BMM结果得到歧义子串计算概率,概率更大的子串判断为正确切分.(这部分代码见文末Github链接)
5 评价指标
本分词实验采用准确率,召回率和F1作为评价指标,它们的计算方法如下:
Precision = 正确切分出的词的数目/切分出的词的总数
Recall = 正确切分出的词的数目/应切分出的词的总数
F1 = 2*Precisiton*Recall/(Precision+Recall)
本实验结果如下:
实验结果可见进行语义消歧的分词方法具有更高的效果。
附:
项目源码
网友评论