[NLP]分词
分词是NLP的基本功能之一,现在发展比较成熟了,目前比较热门的分词工具有jieba,snownlp,pkuseg等等。分词工具的使用是比较简单的,具体查询相应的github项目即可,上面有比较好的示例。本文我们主要讲解一下分词的相关算法:前向最大匹配,后向最大匹配,语言模型,维特比算法等。现分别讲解如下。
前向最大匹配算法
一句话总结:根据参数最大匹配长度max_len,获取一句话中的最大匹配长度的子句,逐步判断子句是否在词典中,是则分词成功,否则删除子句中的最后一个字再进行判断,子句是否在字典中。
输入:一句话sent,词典dic,最大匹配长度max_len
输出:分词后的单词列表words
①获取sent中最大匹配长度的子句sub_sent,判断sub_sent是否在词典dic中
②如果在列表中,则将sub_sent存放进words中,原句sent更新为sent-sub_sent;
③否则,sub_sent中删除最后一个字,判断sub_sent[:-2]是否在词典中
④重复上述步骤,直到sent句子为空为止。
举例:sent = 我要去上学了,词典 = [我,要去,上学,了,上学了,要,去],max_len = 5
①sub_sent = 我要去上学,不在词典中,则将其更新为:sub_sent = 我要去上
②sub_sent = 我要去上,不在词典中,将其更新为:sub_sent = 我要去
③sub_sent = 我要去,不在词典中,将其更新为:sub_sent = 我要
④sub_sent = 我要,不在词典中,将其更新为:sub_sent = 我
⑤sub_sent = 我,在词典中,因此words = [我]
⑥顺移一位,sub_sent = 要去上学了,不在词典中,更新为sub_sent = 要去上学
⑦sub_sent = 要去上学,不在词典中,更新为sub_sent = 要去上
⑧sub_sent = 要去上,不在词典中,更新为sub_sent = 要去
⑨sub_sent = 要去,在词典中,words = [我,要去]
⑩顺移一位,sub_sent = 上学了,在词典中,words = [我,要去,上学了]
最终返回的分词结果是:[我,要去,上学了]
后向最大匹配算法
前向最大匹配取前max_len个字符,后向最大匹配取后面max_len个字符。
举例:sent = 我要去上学了,词典 = [我,要去,上学,了,上学了,要,去],max_len = 5
①sub_sent = 要去上学了,不在词典中,则将其更新为:sub_sent = 去上学了
②sub_sent = 去上学了,不在词典中,将其更新为:sub_sent = 上学了
③sub_sent = 上学了,在词典中,words=[上学了]
④顺移一位,sub_sent = 我要去,不在词典中,将其更新为:sub_sent = 要去
⑤sub_sent = 要去,在词典中,因此words = [要去,上学了]
⑥顺移一位,sub_sent = 我,在词典中,words=[我,要去,上学了]
最终返回的分词结果是:[我,要去,上学了]
最大匹配的缺点:
①不够细分(有可能更好)
②局部最优
③效率(max_len)
④歧义(不能考虑语义)
考虑语言模型(考虑语义)
语言模型就是为了计算一句话符合语义的程度,通过计算一句话的概率表示这句话的自然程度(或者说符合语义的程度)
过程:输入 -> 生成所有可能的分割 -> 选择其中最好的分词组合(工具,如unigram LM)
假设s1 = [我,要去,上学了],s2 = [我,要,去,上学,了]
分别计算概率:p(s1)=p(我,要去,上学了)=0.2,
p(s2)=p(我,要,去,上学,了)=0.4,可知,s2的分词效果更好。
这是unigram LM的模型,考虑了语义,选择最好的分词组合。(关于语言模型)
缺点:复杂度高,效率低;概率计算有可能会溢出(解决办法是用log,这样乘法就变成了加法)
维特比算法(解决效率问题)
生成所有可能的分词后,可以将其转化成图来做,如下面例子所示。
转化成图之后,计算最佳的分词组合就是计算图的最短路径(之所以最短路径是取了词的概率的负对数,这样可以计算最小值),可以用维特比算法,核心是动态规划。
总结
分词的方法如下:
基于匹配规则的方法(最大匹配算法)
基于概率统计的方法(LM,HMM,CRF)
——来源于贪心科技NLP讲解