vlambda博客
学习文章列表

中文分词中的匹配方法——机械分词法

中文分词 /Chinese Word Segmentation

近几年中文分词技术逐渐运用在很多领域。中文分词是自然语言处理的重要步骤。

分词就是将句子、段落、文章等连续的长文本,按照一定的规范重新组合分解,使其成为以字、词为基本单位的数据结构,从而方便后续的处理分析工作


为了让计算机能够更快理解中文文章,就需要提取出文章词与词分开。

对于我们新闻媒体领域而言,中文分词不仅是机器翻译等高级任务的基础、新闻自动归档任务的基础,也是人工智能新闻采写编辑的重要步骤。



中文分词相对于其他语言的分词来说有更大的难度

因为中文的单词之间没有间隔,需要通过语义来进行单词之间的匹配。这对于计算机来说具有非常大的挑战性。

所以针对中文单词的匹配,诞生出了各种技术


中文的分词方法一共分为了三类:


·机械分词方法

·基于统计的分词方法

·机器学习分词方法


其中机械分词方法是三者中最传统与最常见的方法



机械分词法 

它是基于字典的分词方法,顾名思义就是将单词与字典中的词条进行匹配。如果识别到的一个词在字典中有出现就算识别成功。


按照不同的识别顺序,匹配方法又分为了正向匹配法逆向匹配法

按照不同长度优先匹配,又可以分为最大匹配法最小匹配法


我们最常见的匹配方法有正向最大匹配法、逆向最大匹配法与双向匹配法。


#以“我们在野生动物园玩“这个短句为例:

正向最大匹配法】:先确定最长词的字数,接着从左到右,按照最大长度依次递减,直到出现在词典中存在的词,将词语截取下来。比如设定最大长度为5。机器就会从左到右选取五个字:”我们在野生”,显然这不是一个词语。于是依次递减一个字,“我们在野”、“我们在”都不是存在于词典中的词语。直到出现“我们”,将这个词语截取下来。紧接着又从“在”开始往右的5个字依次递减,直到出现“在野”。继续从”生“开始往右的5个依次递减,出现”生动“。但是发现最后的三个字都无法组成词语,所以单独截取出来。这样正向最大法划分后形成的字段是:我们/在野/生动/物/园/玩。


逆向最大匹配法】:与正向相反,逆向是从右到左依次减少字数进行词语的划分。最后形成的字段是:我们/在/野生动物园/玩。


双向匹配法】:我们可以看到无论是正向还是逆向,都不能够很精准进行词语划分。所以为了达到更高的精准度,有人提出了双向匹配法。即两种算法都要进行一遍,最后输出大颗粒词多且单字词少的结果。所以对比以上输出的两个字段,逆向最大匹配法的词数量少,大颗粒词更多,单字的单词少。最终应该输出的是逆向最大匹配法的结果。


·在编写中文分词代码时我们会先导入词典:

def read_dict(path): words_dict = [] with open(path, 'r') as r: line = r.readlines() # print(line) for i in line: word = i.split(',') words_dict.append(word[0]) return words_dict  window_size = 5


·正向最大匹配法:

def fmm(source, words_dict): len_source = len(source) # 原句长度 index = 0 words = [] # 分词后句子每个词的列表  while index < len_source: # 如果下标未超过句子长度 match = False for i in range(window_size, 0, -1): sub_str = source[index: index+i] if sub_str in words_dict: match = True words.append(sub_str) index += i break if not match: words.append(source[index]) index += 1 return words


·逆向最大匹配法:

def bmm(source, word_dict): len_source = len(source) # 原句长度 index = len_source words = [] # 分词后句子每个词的列表  while index > 0: match = False for i in range(window_size, 0, -1): sub_str = source[index-i: index] if sub_str in words_dict: match = True words.append(sub_str) index -= i break if not match: words.append(source[index-1]) index -= 1 words.reverse() # 得到的列表倒序 return words


·双向匹配法:

在上面的基础上,引入比较取舍的程序:

def bi_mm(source, word_dict): forward = fmm(source, words_dict) backward = bmm(source, words_dict) # 正反向分词结果 print("FMM: ", forward) print("BMM: ", backward) # 单字词个数 f_single_word = 0 b_single_word = 0 # 总词数 tot_fmm = len(forward) tot_bmm = len(backward) # 非字典词数 oov_fmm = 0 oov_bmm = 0 # 罚分,罚分值越低越好 score_fmm = 0 score_bmm = 0 # 如果正向和反向结果一样,返回任意一个 if forward == backward: return backward # print(backward) else: # 分词结果不同,返回单字数、非字典词、总词数少的那一个 for each in forward: if len(each) == 1: f_single_word += 1 for each in backward: if len(each) == 1: b_single_word += 1 for each in forward: if each not in words_dict: oov_fmm += 1 for each in backward: if each not in backward: oov_bmm += 1 # 可以根据实际情况调整惩罚分值 # 这里都罚分都为1分 # 非字典词越少越好 if oov_fmm > oov_bmm: score_bmm += 1 elif oov_fmm < oov_bmm: score_fmm += 1 # 总词数越少越好 if tot_fmm > tot_bmm: score_bmm += 1 elif tot_fmm < tot_bmm: score_fmm += 1 # 单字词越少越好 if f_single_word > b_single_word: score_bmm += 1 elif f_single_word < b_single_word: score_fmm += 1  # 返回罚分少的那个 if score_fmm < score_bmm: return forward else: return backward


除了以上介绍的常见中文分词方法——机械分词法,近几年逐渐诞生出了更加智能化、准确化的中文分词方法。让机器不再用这种机械的方式去拆分语句。而是通过对语义的理解去进行更精准的划分。应用的领域也越来越广泛,例如:机器翻译(MT)、语音合成、自动分类、自动摘要、自动校对等。


但是作为自然语言处理中的重要环节,中文分词还面临着很多挑战。比如:热词、流行词不断出现给机器学习造成了很大的困难。汉字的不同搭配容易造成歧义,导致多种划分标准。我国专门研究中文分词的机构也很少,大部分都集中在科研院校当中。


所以中文分词面临着许多机遇和挑战,追求效率准确率是中文分词未来的发展目标。要想让中文分词更好应用服务于其他领域,就需要先对其深刻研究,将机器人性化。