基于字符串匹配分词。将待分的字符串与一个充分大的机器词典中的词条进行匹配。
正向最大匹配: 对输入的句子从左至右,以贪心的方式切分出当前位置上长度最大的词,组不了词的字单独划开。其分词原理是:词的颗粒度越大,所能表示的含义越精确。
逆向最大匹配: 原理与正向最大匹配相同,但顺序不是从首字开始,而是从末字开始,而且它使用的分词词典是逆序词典,其中每个词条都按逆序方式存放。在实际处理时,先将句子进行倒排处理,生成逆序句子,然后根据逆序词典,对逆序句子用正向最大匹配。
双向最大匹配: 将正向最大匹配与逆向最大匹配组合起来,对句子使用这两种方式进行扫描切分,如果两种分词方法得到的匹配结果相同,则认为分词正确,否则,选取分词结果中单个汉字数目较少的那一组。
小结: 基于词典的分词方法简单、速度快,效果也还可以,但对歧义和新词的处理不是很好,对词典中未登录的词没法进行处理。
该方法主要**基于句法、语法分析,并结合语义分析,通过对上下文内容所提供信息的分析对词进行定界,**它通常包括三个部分:分词子系统、句法语义子系统、总控部分。在总控部分的协调下,分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义进行判断。这类方法试图让机器具有人类的理解能力,需要使用大量的语言知识和信息。由于汉语语言知识的笼统、复杂性,难以将各种语言信息组织成机器可直接读取的形式。因此目前基于知识的分词系统还处在试验阶段。
从大量已经分词的文本中,利用统计学习方法来学习词的切分规律,从而实现对未知文本的切分。随着大规模语料库的建立,基于统计的分词方法不断受到研究和发展,渐渐成为了主流。
常用的统计学习方法有:隐马尔可夫模型(HMM)、条件随机场(CRF)和基于深度学习的方法。
jieba是基于统计的分词方法,jieba分词采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合,对于未登录词,采用了基于汉字成词能力的HMM模型,使用了Viterbi算法。
**小结:**基于统计的分词方法能很好地处理歧义和新词问题,效果比基于词典的要好,但该方法需要有大量人工标注分好词的语料作为支撑,训练开销大,就分词速度而言不如前一种。
Jieba分词 https://github.com/fxsjy/jieba
SnowNLP https://github.com/isnowfy/snownlp
LTP http://www.ltp-cloud.com/
HanNLP https://github.com/hankcs/HanLP/
jieba分词项目地址
**原理:**基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (Directed Acyclic Graph,DAG);采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合;
对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法。
结巴分词首先会依照结巴默认的统计词典dict.txt构造前缀词典。
dict.txt含有近35万的词条,每个词条占用一行,其中每一行有3列,第一列为词条,第二列为对应的词频,第三列为词性,构造前缀词典需要用到前两列。
具体做法为:首先定义一个空的python字典,然后遍历dict.txt的每一行,取词条作为字典的键,词频作为对应的键值,然后遍历该词条的前缀。如果前缀对应的键不在字典里,就把该前缀设为字典新的键,对应的键值设为0,如果前缀在字典里,则什么都不做。
这样等遍历完dict.txt后,前缀词典就构造好了。在构造前缀词典时,会对统计词典里所有词条的词频做一下累加,累加值等计算最大概率路径时会用到。
基于前缀词典,对输入文本进行切分;e.g.:
对于‘去’:没有前缀,只有一种划分方式;
对于‘北’:有‘北’,‘北京’,‘北京大学’三种划分方式;
对于‘大’:有‘大’,‘大学’两种划分方式……
依次类推,可以得到每个字开始大前缀词的划分方式。
对于0: [0],表示位置0对应的词,就是0 ~ 0,就是“去”;对于1: [1,2,4],表示位置1开始,在1,2,4位置都是词,就是1 ~ 1,1 ~ 2,1 ~ 4,即“北”,“北京”,“北京大学”这三个词。
对于每一种划分,都将相应的首尾位置相连,例如,对于位置1,可以将它与位置1、位置2、位置4相连接,最终构成一个有向无环图。
在得到所有坑的切分方式构成的有向无环图后,其从起点到终点有多条路径(即多个分词结果);我们需要计算出最大概率路径,即按照这种方式切分后的分词结果的概率最大。
采用维特比算法进行计算。
对未登录词采用HMM模型进行分词
当出现没有在前缀词典里收录的词时,会采用HMM模型进行分词
结巴分词已经内置了训练好的状态初始概率、状态转移概率和状态发射概率。
句子会作为观测序列,当有新句子进来时,具体做法为:先通过Viterbi算法求出概率最大的状态序列,然后基于状态序列输出分词结果(每个字的状态为B、M、E、S之一)。(B, M, E, S): {B:begin, M:middle, E:end, S:single}
如果切出了词典中没有的词语,效果不理想,结巴里也可以关闭新词发现。
纠错是一个重要又不重要的领域。 不纠错下游工作其实也能进行,只是会影响效果、体验(例如word2vec之类大样本训练任务)。但有时候用户体验直接影响收入(如电商搜索,输入法,校对等,此时纠错又显得比较重要。)
纠错相对更偏系统工程(经常是其它nlp任务的上游,对响应速度要求较高)
纠错场景:
输入法(拼音、英文)
通用搜索(百度、搜狗)
垂类搜索(电商、社区、图片)
智能问答
训练语料清洗
基本上凡是涉及用户输入的场景(nlp)都需要纠错
why:
文本输入(输入法): 直接影响输入体验
语义理解(搜索、对话): 直接影响(商品、候选回答等的)召回效果
数据预处理(训练样本,数仓):过脏的数据无法用来做分析和训练,虽然可以假设正确样本占多数,
校对(出版社):直接影响用户阅读理解
纠错常与分词一起,具体谁在前不一定;有分词纠错同时进行的
英文NER可以在纠错之前,中文NER一般在纠错之后
中文较少因为纠错让实体词变为非实体词
编辑距离
处理方法与中文相同
一个字符串需经过多少次变化后变为另外一个字符串,工业上一般编辑距离不超过2。
出错场景:
处理方法:
输入字符串=s
触发条件:oov or unigram词频太低
候选词(方法一)
先尝试ed=1,
少字符(s的每个位置加入a-z)
多字符(删除s的每个字符)
错字符(把s的每个字符用a-z代替,可以基于字符位置(26键)做过滤)
顺序错(把s相临的每两个字符交换)
再试ed=2
把ed=1的每个字符串再遍历一遍ed=1的处理
不在词表的去掉
基于unigram词频去掉值太低的
BK-Tree
成立条件:
d(x,y)=0 当且仅当x=y
d(x,y)=d(y,x)
d(x,y)+d(y,z)>=d(x,z)
d(x,z)=a, d(x,y)=b, 求f=d(y,z)的范围
d(x,z)+d(z,y) >= d(x,y) => f>=b-a
d(y,x)+d(x,z) >= d(y,z) => f<=b+a
a=搜索范围、b=query与节点的距离、f=节点与子节点的距离
构造
以任一单词作为根
1. 插入时先计算与该子树节点的距离
2. 插入到该子树对应子节点下
3. 循环1、2直到成为叶子节点
查询
求与query编辑距离<=a的单词
计算query与子树根节点的距离
然后往下找出距离=[b-a,b+a]之间的子树
b=query与节点的距离
逐层往下最终到叶子节点
当a较小时有价值,较大时与遍历区别不大
候选词选择
尝试纠错
合并召回统一基于unigram排序
ed=1扣积分,ed=2扣更多分
输入为句子
计算整句但概率(ppl or lm(2gram or lstm))
选择概率最大的那个词,同样需要针对ed做降权
排序权重学习
词频、纠错排序等
用户有显式返回场景(输入法,补全框)
样本稀疏,一般针对人群
p(I)就是语言模型,类似hmm的发射概率
(│)=((│)())/()
直接统计p(wrd|err)也是可以的
朴素贝叶斯(│)的X是多个样本(词),没法直接统计结果
err过于稀疏
p(wrd)本来已有,所以统计p(err|wrd)并不比p(wrd|err)费力,p(x)计算相对值不需要
常见用法
召回,基于先验代替p(err|word)
编辑距离(拼音混淆、方言等)
排序
用LM做排序
因为每种错误的频率过低,概率不好统计
可以混合使用
对高频错误计算p(wrd|err)
先要正常搜索候选,再根据ed+p(wrd|err)排序
不在错误表里的依然使用前面的方法
后面的pattern识别即是此方法
real word error
方法一:
每个词都认为是错词,找到N个候选
然后类似‘最短路径分词’,找到概率最优的那条(经常用Viterbi)
也会对ed=1/2降权
方法二:
基于LM(2gram等)找出概率突降的位置
对该词寻找候选词令整句ppl最高
场景:
输入法
难度最高
输入场景(搜索、评论)直接输拼音
与输入法不同,拼音本身就难识别,所以用户一般会自查
至少默认声母都是正确的
无法给用户提供候选集,天然也不适合做大量召回
中文纠错(音似导致的错误,恢复拼音再纠错)
词已经确定,相对容易
9键经常不进行纠错
因为候选集本身就很多,错误概率也不高
候选的拼音很多,对应的字词就更多了
拼音纠错法:
以前:
词库为映射表,nihao->你好
长句、非标准词序输入支持非常弱
必须用户逐字/词的指定
无法给出合理的默认值
即使给出也多为词的硬关联,语义合理性差
现在:
使用语言模型词库(bigram&unigram)
1)基于声母拆字
2)基于拆好的拼音查找候选字
3)基于bigram&unigram找出概率最高的序列
hmm(Viterbi)/最短路径
未来:
手机性能增长、模型压缩、网速大增(完全基于在线计算)
基于已上屏的上下文,用dl模型推荐出当前最可能的输入
做过尝试,代价比较高,效果凑合
直接基于拼音与输入做端到端的训练
现在长句一般也会发送到云端做解析
但依然是先拆字再计算概率,只是用更重的模型(3/4gram, lstm等)
对响应时间要求依然很高
拼音常见错误:
常见的拼音错误
输入错误,与英文类似
混淆音字词、方言(l-n/f-h/yie-ye/iou-iu/u-v)
gu|a->ai|wu 挂物(怪物)攻城奖励
s|en->un|zi 森子兵法 → 孙子兵法
前后鼻音: 打战片 → 打仗片
UV不分:鲁政俏佳人 → 律政俏佳人
LN不分: 晚良 → 晚娘
平翘舌: 甑([zèng])嬛传 → 甄嬛传
多音字
同音字
迟暮刚宪 →赤木刚宪
豌豆夹 → 豌豆荚
徐铮 → 徐峥
纠错流程:
先断字
每种断法都作为下一步的候选
基于某种断字方法
进行ed=1 or 2的候选扩充
如果增删改的字符让新字符串不构成拼音则抛弃
声母只能代替声母,韵母只能代替韵母
也可使用bk-tree搜索
包括混淆音、方言等问题
拼音编辑距离
in->ing/an->ang/z->zh/l->n
unigram/bigram
使用的是断字之后字词本身的uni/bigram
方言混淆音的召回不降权
中文常见错误:
词本身错
同音字词 (拼音输入法)
配副眼睛-配副眼镜
拼音错误(编辑距离)
拼风-屏风
形似字错误 (笔划、五笔、二笔)
高梁-高粱
混淆音字词、方言(l-n/f-h/yie-ye/iou-iu/u-v)
流浪织女-牛郎织女,打战片-打仗片,ln不分:晚良-晚娘
语法错误
多字/少字
字词顺序颠倒
周伦杰-周杰伦 (一般两个以上颠倒较难纠正)
语法错误
想象难以->难以想象
用词错
知识错误
传统算法基本无法解决。只能通过数据挖掘出一些常见模式。
名人人名、身高等信息错误
英文场景也会遇到类似错误
语法错误
1) 做句法分析计算句法概率去识别,然后基于句法匹配去纠正
正确率也不高
2) 用NMT模型直接输出
1 错误检测:
大量的工程工作
可控优先
困惑集
基于每个单字可能出错的同音同形字
假设每个字都可以错,全部找出候选用ngram/ppl/等找出最优组合。
错词库、热词库pattern
可以用字典树查找
置信较高可直接替换
其它作为候选
泥(你)好->水泥好贵
难点:错词库的建立,置信度的评估(错误数/共现数)
分词
凡是 单字 和 不在词表的词 都认为可能出现错误
如果分词错误可能导致误判
王青水你好->王青水泥好
ML
MaxEnt最大熵模型作为分类器
SVM作为分类器
神经网络作为识别器
LM语言模型式,类似ngram
基于前面(或双向)文字预测当前位置可能出现的字
序列标注问题
逐字or逐词预测是否正确
2 候选词
字形类似
每个字都有一个同形映射表,查找。都属于困惑集
同音、类似音、拼音错误
汉字恢复为拼音
可做先验,恢复的汉字声母首字母都是正确的
最多就是l/n方言式固定变换
基于拼音找出候选词
与拼音纠错相同
问题
对于少字情况无法通用处理
单字独立成词,常用汉字7000多,无法逐一尝试增加
只能使用pattern解决常见情况
3 错误纠正
其实是排序
基于LM
ngram计算用候选字词代替当前字词分数最高的那个
如果候选字的个数不等,则不好比
计算整句ppl最高的那个
ppl依赖的ngram可用词级别
字级别远距离识别较差,对整体评分不利
nn给整句通顺度打分
与ppl类似,但可以识别远距离关系
HMM
正确的字为隐藏状态
转移概率(2gram),发射概率(该字发生该错误的概率)
去掉发射概率也可直接用viterbi解码
原 理还是语言模型
SVM
基于窗口
前后几个字符的特征、是否在ngram内,分数
可以用来识别
基于整句
特征工程(LM信息、词频、编辑距离、是否同音近似音等)
只能用来排序
纠错流程(pycorrector)
1)直接搜索有没有常见错误
直接根据映射纠正
保守期间可以作为候选
2)分词
所有不在词表里的词或单字都可能是错误
都作为候选
3)基于语言模型找出概率值较低的那些字
2gram与3gram取平均
再求方差,取方差高于阀值的
4)生成候选
把所有疑似错字找到对应同音、同型字,作为正确候选
5)计算用候选正确字代替后的ppl
1. 加载停用词
def load_stop_words(stop_word_path):
'''
加载停用词
param stop_word_path:停用词路径
return: 停用词表 list
'''
## 打开文件
file = open(stop_word_path, 'r', encoding='utf-8')
## 读取所有行
stop_words = file.readlines()
## 去除每一个停用词前后 空格 换行符
stop_words = [stop_word.strip() for stop_word in stop_words]
return stop_words```
## 词的标准化
```python
在这里插入代码片
2. 过滤字符
def clean_sentence(line):
line = re.sub(
"[a-zA-Z0-9]|[\s+\-\|\!\/\[\]\{\}_,.$%^*(+\"\')]+|[::+——()?【】《》“”!,。?、~@##¥%……&*()]+|题目", '',line)
words = jieba.cut(line, cut_all=False)
return words
在这里插入代码片
否。
可以通过修改模型训练中的loss权重,比如罗辑回归中进行case_weight的调整,adaboost中对样本错分权重的改变等等。
尽量避免使用合成采样的方式去做数据填充,总结如下:
当缺失值占比在可接受的范围以内的时候才需要进行填充,如果缺失值大于50%以上的时候,可以选择进行二分化,如果缺失值大于80%可以完整删除该列而不是强行去填充
把全部结果都embedding化,对空值或者缺失值按照一定规则生成若干个hold位,以hold位的向量结果作为缺失值的结果
- 可以参考YouTube中的新商品向量生成逻辑
- bert中的[UNK]向量,[unused]向量
如果我们能在原始数据上发现明显规律,比如整体数据满足高维多元高斯分布,则可以通过未知列补全缺失列的值
在缺失量特别少(通常认为小于1%)的时候,可以随机生成
归一化(max-min)
标准化(z-score)
作用
总结
常用模型
截断
二值化
分桶
离散化
缩放
特征交叉
非线性编码