最近研究NLP的技术,搞了掘金小册子入个门,随手做个笔记
内容源于掘金小册《深入理解NLP的中文分词:从原理到实践》
背景
- 自然语言处理基础技术
- 自然语言处理应用技术
基础知识
- 中文分词的四大难题
- N-Gram切词法
- 解决中文分词歧义问题
- 解决未登录词问题
进阶知识
- HMM-隐马尔可夫模型
- CRF-条件随机场
业务案例
- 关键词挖掘
- 文本相似度
- 自动摘要
下面细讲每点的主要内容
自然语言处理基础技术
- 词法分析:分词、词性标注、实体识别
- 词向量表示:语义挖掘、词义相似度
- 文本相似度:计算两个短文本之间的语义相似度,实现推荐和排序
- 依存句法分析:自动分析文本中的依存句法结构信息
- DNN语言模型:判断一句话是否符合语言表达习惯
自然语言处理应用技术
- 文本纠错:识别文本中的错别字,给出提示及正确的建议
- 情感倾向分析:对包含主观信息的文本进行情感倾向性判断
- 评论观点抽取:分析评论关注点和观点,输出标签及观点极性
- 对话情绪识别:识别会话者所表现出的情绪类别及置信度
- 文本标签:输出能够反映文章关键信息的多维度标签
- 文章分类:输出文章的主题分类及对应的置信度
- 新闻摘要:抽取关键信息并生成指定长度的新闻摘要
- 文本审核:对敏感内容进行识别和过滤
- 文本翻译:通用翻译、语音翻译、拍照翻译
中文分词的四大难题
1、如何清晰地界定中文词汇
中文分词工具的好或坏,至少需要有一个清晰的评判标准,即中文词汇的界定
举例,“科教兴国”既可以整体切分成「科教兴国」,也可以切碎成「科教」和「兴国」 ,都符合百科里面的定义,也都合情合理
后面的章节我会详细讲解中文分词工具是如何处理这类问题的
2、是先分词后理解,还是先理解后分词
很多人去尝试这种先理解后分词的方案,其核心思想就是把分词的决定放在句法分析的过程中去解决,这样就需要一个强大的基于句法-语义规则的句子分析系统中文分词歧义的问题
然而这样的一套中文分词工具严重依赖人工规则的质量和数量,即便在不考虑成本的情况下,在国际中文分词评测活动中还是不敌基于统计学习的中文分词工具
结论就是在中文分词解决方案的选择上,先分词后理解得到了理论和评测数据的双重肯定。
3、中文分词歧义的问题(N-Gram切词法)
交集型歧义
用一个直观的形式表示交集型歧义就是:ABC,即可以切分成AB/C,也可以切分成A/BC
工作的和尚未工作的
工作 / 的 / 和 / 尚未 / 工作 / 的
工作 / 的 / 和尚 / 未 / 工作 / 的
组合型歧义
同样用一个直观的形式表示组合型歧义就是:AB,即可以组合成AB,也可以切分成A/B
希望你们再创新的业绩
希望 / 你们 / 再 / 创 / 新 / 的 / 业绩
希望 / 你们 / 再 / 创新 / 的 / 业绩
4、未登录词的识别问题
通过大量的评测结果表明,未登录词对精度的影响是歧义问题的5倍以上
未登录词其实不难理解,就是没有被收录到分词词典里的词。这样的词类型有很多:网络新词(最难)、人名、机构名、缩写词、新增词等等。
然而这些类型的词往往对实际业务有着很大的价值,是分词结果考察的重点。
当然已经有了很多的方法,可以自动识别未登录词,比如:HMM、CRF等。
HMM:隐马尔可夫模型,是统计模型,它用来描述一个含有隐含未知参数的马尔可夫过程。
CRF:条件随机场,是给定一组输入序列条件下另一组输出序列的条件概率分布模型。
N-Gram模型切词法
先了解一下统计语言模型
统计语言模型,是将每句话都看作是由单词组成的序列,S=(w_{1}, w_{2}, w_{3}, …, w_{n}),然后对每句话S评定一个概率P(S)=P(w_{1}, w_{2}, w_{3}, …, w_{n}),若该概率越高,则说明该句话越符合语法,越像人话。
利用条件概率将计算公式改写成:
可以理解为将w_{1}到w_{n}同时发生的联合概率,替换成了w_{1}发生的概率,加上w_{1}发生情况下w_{2}发生的概率,并以此累加而得到的概率,这样就离可计算、可泛化更近了一步。
因为一个完整的句子作为统计单位,其可统计的样本数据是非常有限的,所以得到的统计结果缺乏普遍性,如果出现一个不曾在样本数据里的句子时,就无法判断其概率了。
实际情况是,在一句话里一个词是否可能出现,依赖的是它邻近的几个词,距离很远的词已经起不到多大的作用了。
推导到这里,就需要引出马尔可夫假设,来进一步简化计算公式
马尔可夫假设:就是每个词出现的概率只跟它前面的少数几个词有关。
当m=1时,是一个一元模型,Uni-Gram model:
很容易发现,当m=N时,我们就得到了N-Gram model,这个推导过程就说明了什么是N-Gram模型。
N-Gram模型利用统计信息找出一条概率最大的路径,得到最终的分词结果。
以“南京市长江大桥”为例,将其切分成一个有向无环图(DAG)
假设S是一段文本,W是S上所有可能的切分路径。我们只要能求解出条件概率P(W|S)的最大值,就能得到我们想要的切分路径了
根据贝叶斯公式:
可以理解为W,S同时发生的概率除以S发生的概率,就是S发生情况下W发生的概率,同时W,S同时发生的概率,也可以理解为W发生的概率乘以W发生情况下S发生概率
由于P(S)为归一化因子,而P(S|W)恒为1,因此我们只需要求解P(W)的最大值即可,这就是N-Gram模型了。
借鉴N-Gram模型的思想,将中文句子按字进行N-Gram的切分。
不难发现,在N不同的取值范围里,是可以切分出语义正确的词汇,当然这里面也包含了大量的语义错误的噪声词。
但在一些特殊的业务场景里,这样的结果是非常有价值的,如:新词发现、文本挖掘等。
解决中文分词歧义问题
交集型歧义
解决方法:
最大匹配法
- 正向最大匹配法,是从左向右扫描切分词的最大匹配
- 逆向最大匹配法,是从右向左扫描切分词的最大匹配
- 双向最大匹配法,是通过对比正向和逆向的匹配结果,然后按照最大匹配原则,选取分词总数最少的作为结果,来决定最优的切分路径。
结论:
最大匹配法可以解决90%的句子,正向最大匹配法和逆向最大匹配法的结果完全重合且正确,只有9%的句子两种方法的结果不一样,但其中必有一个是正确的,只有1%的句子,无论那种方法结果都是错误的
特殊规则法
**规则一:**把一些字与字之间搭配的优先级事先定义好
**规则二:**一个适用范围更广的规则,整理一份不能单独成词的字表
如何决定全局评判标准:(解决组合型歧义)
最大匹配原则,添加上**“不成词字表”的规则**,利用动态规划求解分词总数最少
小结:词总数最少法,切分路径结果里有多少词,就罚多少分,每出现一个不成词的单字,就加罚一分,罚分最少的就是最优的分词结果。
在此算法具体实现层面,并不需要穷举所有的切分可能,利用动态规划求解最短路径效率会更高。
动态规划
利用动态规划,则可以解决任何一个图论中最短路径问题,效率更高。其思想是通过把原复杂问题分解为相对简单的子问题的方式来求解。
动态规划的设计有一定的模式,一般要经历4个步骤:
- 划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。注意划分后的阶段一定要有序,否则问题无解。
- 确定状态和状态变量:将问题发展到各个阶段时处于的各种客观情况用不同的状态表示出来。
- 确定决策并写出状态转移方程:因为决策和状态转移有着必然的联系,状态转移就是根据上一阶段的状态和决来导出本阶段的状态。
- 找出边界条件:给出的状态转移方程是一个递归式,需要一个终止条件或边界条件。
解决未登录词问题
基于统计的抽词算法——凝固度
从语料抽取,抽号的词与现有的词典比较,发现新词
引入重要的统计学概念——大数定律。
大数定律:在相同条件下,随着随机试验次数的增多,频率越来越接近于概率。注意大数定律陈述的是一个随着n趋向于无穷大时频率对真实概率的一种无限接近的趋势。
用N-Gram方法将语料库切分成各种序列,一元、二元、三元,根据需求切分更多元的序列,统计各元素的频数
仅仅是靠频数还是不够的,因为一个经常出现的元素有可能不是一个词,而是多个词组成的词组。假如,语料库里“的飞机”出现的频数要高于“飞机场”出现的频数,但显然“的飞机”应该被切分成「的」和「飞机」,需要凝固度帮助解决。
凝固度:用来衡量一个字组合片段里面字与字之间的紧密程度,凝固度越高,说明这个组合片段(这个词)越不可分
在计算语言学中,PMI(Pointwise mutual information,逐点互信息)被用来度量词搭配与关联性:
针对一个词有多种搭配组合的情况,如“飞机场”可以由「飞机」+「场」组合,也可以由「飞」+「机场」组合,可以改进一下PMI公式:
公式的理解:C{m}_{1}表示要求解的「词」,如:“飞机场”。P(C{m}{1})表示这个「词」出现的概率,\prod{P(C^{j}{i}})表示这个「词」的各种搭配组合的随机概率,如:「飞机」+「场」、「飞」+「机场」,最后取这里面最小值代这个「词」的凝固度。
取最小值,是为了避免错误的切分组合过高地估计了凝固度。
另一个重要的算法——自由度
还需要了解一个重要的概念信息熵,因为自由度算法就是由信息熵概念而产生的。
“信息熵”是“熵”在信息论里的一种表现,表示无序的信息。
信息熵:接收的每条消息中包含的信息的平均量,这个值可以用来衡量文本内容的不确定性。
自由度算法
自由度:一个字组合片段能独立自由运用的程度,自由度越低,说明越不能单独成词
一个「词」和它左边、右边的字搭配越丰富,则这个「词」越独立成词,反之,则这个「词」越像半个词。
一个「词」自由运用的程度是判断它是否成词的重要依据,这恰恰就是信息熵所要度量的问题。我们也就有了自由度的计算公式:
公式的理解:C{m}_{1}表示待处理的「词」,如:“辈子”等,le(C{m}{1})和re(C^{m}{1})则表示的是左邻字集合的信息熵和右邻字集合的信息熵,最后取最小值表示这个「词」的自由度。
这里找到一个比较有趣的做法:基于凝聚度和自由度的非监督词库生成
HMM — 隐马尔可夫模型
HMM隐马尔可夫模型的定义:用来描述一个含有隐含未知参数的马尔可夫过程。
马尔可夫模型是从直接观察前面节点一步步生成后面节点的过程,HMM就是说,前面节点不让你直接观察了,抽象出一组隐藏状态的节点(有点像LSTM的感觉)
CRF — 条件随机场
这里有一个关于CRF更详细的讲解
https://www.cnblogs.com/pinard/p/7048333.html
随机场:由若干个位置组成的整体,当每一个位置按照某种分布随机赋值之后,其全部情况
CRF条件随机场的定义:每一个位置按照条件概率分布随机赋值的随机场。
CRF对比HMM的优势,当我们正确判断一个事情时,需要很多的上下文信息,HMM只考虑了前一个隐藏状态和当前一个观察状态的影响,而忽略掉了之前和之后的状态,CRF考虑了全局的信息,可以充分地学习到全局的信息,获得更多的有效特征,提高模型的判断性能
CRF的实现:
线性链条件随机场
每个字的标注结果都会受到全局的影响,那么如何用一种可量化的计算公式进行表达,就是接下来我们要思考的问题了。我们可以使用条件概率:
P(Y_{i}|X, Y_{1}, Y_{2}, …, Y_{n})
其中Y_{i}表示句子中的第i个字的标注,X表示句子中字的集合,Y_{1},Y_{2}, … , Y_{n}表示句子中其它字的标注。
特别需要注意的是:当X与Y具有相同的结构时,这样的CRF称为线性链条件随机场(linear-CRF)。而词位标注(中文分词)恰恰符合这样的定义。
特征函数:通过函数的形式来描述linear-CRF中的依赖关系(就是特征)
参数含义:
s表示句子
i表示第i个字
l_{i}表示第i个字的标注词位
l_{i-1}表示第i-1个字的标注词位
而返回结果如下:
符合这个特征时,则返回1
不符合这个特征时,返回0
这只是一个特征函数,我们可以根据实际需要,定义一个特征函数集合,用这个特征函数集合来为一个标注序列打分,并据此选出最优的标注序列。
假如仅仅依靠当前字的标注和它前一个字的标注,来分别对标注序列进行打分,然后把这个特征函数集的打分综合起来,最后得到就是标注序列的评分了。计算公式如下:
s_{l}(s, i, l_{i}) + t_{k}(s, i, l_{i-1}, l_{i}) ,其中l = 1, 2, …, L和k = 1, 2, …, K。
需要注意的是:
在linear-CRF中,特征函数分为两类
第一类是定义在Y节点上的节点特征函数,这类特征函数只和当前节点有关,记为:
s_{l}(s, i, l_{i}) ,l=1,2,…L
其中L是定义在该节点的节点特征函数的总个数,i是当前节点在序列的位置。
第二类是定义在Y上下文的局部特征函数,这类特征函数只和当前节点和上一个节点有关,记为:
tk(yi−1,yi,x,i),k=1,2,…K
其中K是定义在该节点的局部特征函数的总个数,i是当前节点在序列的位置。
之所以只有上下文相关的局部特征函数,没有不相邻节点之间的特征函数,是因为我们的linear-CRF满足马尔科夫性。
L和K这两类特征函数的数量并不相同,L是定义在该节点的节点特征函数(如:B、M、E、S)的总个数,而K是定义在该节点的局部特征函数(如:[B, M]、[B, E]等)的总个数。
特征函数的返回结果不是1就是0,即满足条件或者不满足,但实际上不同的特征函数对最终评分的影响程度是不一样的,有的重要,有的作用不大。
但同时采用概率计算,每个特征函数分配一个权值,用以表达这个特征函数的影响力。计算公式如下:
第一个求和是对遍历特征方程j的求和,而第二个求和是对句子里面的每一个位置i进行遍历进行求和。这里只是包含了一种类型的特征函数集,为了方便公式表达,而实际情况我们可以包含多种类型的特征函数集。
对这个评分结果进行指数化和归一化的处理,转换为0到1之间的概率值,方便比较和计算。
假设tk的权重系数是λk,sl的权重系数是μl,则linear-CRF由我们所有的tk,λk,sl,μl共同决定。
此时我们得到了linear-CRF的参数化形式如下:
P(y|x)=1Z(x)exp(∑i,kλktk(yi−1,yi,x,i)+∑i,lμlsl(yi,x,i))
其中,Z(x)为规范化因子:
Z(x)=∑yexp(∑i,kλktk(yi−1,yi,x,i)+∑i,lμlsl(yi,x,i))
回到特征函数本身,每个特征函数定义了一个linear-CRF的规则,则其系数定义了这个规则的可信度。所有的规则和其可信度一起构成了我们的linear-CRF的最终的条件概率分布。
当这些权重值已知的时候,只要有一个句子s,有一个标注序列l,就可以利用上面定义的计算公式对标注序列l进行打分了。
为了得到这些权重,可以采用梯度上升法,通过学习训练数据,获得各个特征的最大权重值
选用梯度上升法进行训练,想让每个特征发挥最大的影响力,假如这个特征函数赋予了最大的权重,对结果还没有什么影响,那么,比最大权重还要小的话,对结果的影响只会更小。
关键词挖掘
关键词挖掘是NLP任务中比较基础的,但却非常重要,它是很多NLP任务的前提条件。关键词的应用非常广泛,比如:SEO、搜索、推荐系统、知识图谱等等。
基于统计特征的关键词挖掘 —— TF-IDF
TF-IDF(term frequency-inverse document frequency)是一种用于信息检索与文本挖掘的常用加权技术,也是一种统计方法,用以评估一个词对于一个文件集或一个语料库中的其中一份文件的重要程度。
TF-IDF的假设是,一个词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
所以,TF-IDF有两层含义,一层是“词频”,另一层是“逆文档频率”(IDF)。它们的计算公式如下:
分母加1是为了避免所有文档都不包含某词时,导致分母为0
缺点是有时候重要的词出现的次数并不多,导致用词频来衡量一个词的重要性时并不全面.
基于词图模型的关键词挖掘 —— TextRank
TextRank算法的基本思想是,将待挖掘关键词的文本进行分词,以固定的窗口大小(可调整)来获得词之间的共现关系,构建一个无向带权图,然后用PageRank迭代计算图中每个节点(词)的rank值,按照rank值排序即可获得关键词。
和 LDA、HMM 等模型不同, TextRank不需要事先对多篇文档进行学习训练, 因其简洁有效而得到广泛应用,与TF-IDF的改进点,考虑了相邻词的语义关系、基于图排序的提取关键词,由于TextRank涉及到构建词图及迭代计算,所以提取速度较慢。
但是,本质上还是基于词频,严重依赖分词结果,如果某词在分词时被切分成了两个词,那么在做关键词提取时无法将两个词黏合在一起(TextRank有部分黏合效果,但需要这两个词均为关键词),而且需要节点(词)不断出现才会生成新的关键词。
基于主题模型的关键词挖掘 —— LDA
LDA是一种主题模型,它可以将文档集中每篇文档的主题按照概率分布的形式给出。同时它是一种无监督学习算法,在训练时不需要手工标注的训练集,需要的仅仅是文档集以及指定主题的数量即可。
如果我们想要还原出“文章确定主题,主题确定用词”的这个过程,就需要一个上帝视角,而LDA就是通过概率和计算的方式,帮我们打开了这个上帝视角。
gensim是一个Python NLP库,里面包含了LDA模型的实现
文本相似度
文本类推荐系统需要的重要特征
文本相似度计算主要有4类方法:
- 基于词向量
- 基于字符
- 基于概率统计
- 基于词嵌入模型
基于词向量 —— 余弦相似度
余弦相似度:通过测量两个向量的夹角的余弦值来度量它们之间的相似性。
- 当两个向量指向相同时,余弦相似度为1
- 当两个向量夹角为90°时,余弦相似度为0
- 当两个向量指向相反时,余弦相似度为-1
文本转成向量的形式,采用Word2Bag模型,利用TF-IDF进一步优化这个向量,为文本的每个词计算一个TF-IDF值,并赋值到原有向量的相同位置,这样每个词对于文本的重要程度就可以体现出来了。
处理短文本(句子)间的相似度,直接用上述方法处理。
处理长文本间的相似度,一般需要使用上关键词挖掘,即用长文本的关键词集合替代长文本的内容。好处:一是向量的维度会降低;二是长文本的重要信息更突出。
基于字符 —— 编辑距离
编辑距离:针对两个字符串的差异程度的量化测量,测量方法是看至少需要多少次的处理才能将一个字符串变成另一个字符串。常用的编辑距离是莱文斯坦距离
编辑距离处理短文本间的相似度还可以,但要处理长文本就很困难了。同时,编辑距离算法本身有很强的局限性,很难处理同一个意思多种表达的情况。
直接使用python-Levenshtein包来方便计算编辑距离
基于概率统计 —— Jaccard系数
Jaccard系数:主要用于计算样本间的相似度,用样本交集的个数除以样本并集的个数。
关于文本相似度,我们可以将文本通过分词转换成词的集合,这样就可以利用Jaccard系数计算文本间的相似度了。
用sklearn的CountVectorizer来帮助统计词频
基于词嵌入模型 —— Word2vec
上面三种都有缺失语义的问题
一开始为了把文本进行数值化,使用One-Hot编码,但是当词汇表非常大的时候,导致编码后的向量维度非常高,而且不带有任何语义信息,向量空间稀疏。
Word2vec采用神经网络实现,有两种实现模型:
- CBOW是给定上下文来预测input word,对于小数据集比较有效
- Skip-gram是给定input word来预测上下文,对于大数据集比较有效
腾讯的词向量数据,并且这些公开的Word2vec模型所使用语料库规模都比较大,效果会更好
Word2vec就是利用神经网络解决缺失语义的问题,一个词经过Word2vec模型的编码,就可以学习到上下文的信息。此时,这个词的向量化表达就具有了语义。
当词有了向量化表达,那么文本也可以用向量化表达,最简单的做法就是将句子中所有词的向量累加求平均值。之后,我们再使用余弦相似度进行计算,就可以得到带有语义信息的文本相似度了。
这种方法的实际表现效果已经很好了,不过我们还可以为文本中每个词添加一个权重,比如:TF-IDF,来进一步提高效果。
自动摘要
摘要的本质就是在损失最小信息量的情况下,最大程度表达原文的信息量。
信息熵的概念,这恰恰和信息量有直接关系。
信息熵是接收的每条消息中包含的信息的平均量,这个值可以用来衡量文本内容的不确定性。
通过阅读摘要,应该能够降低对原文的不确定感,摘要文本应当以最小的信息损失来推断原文内容。
如何衡量这种不确定性降低的程度,就需要引出一个新的概念 —— 交叉熵。
交叉熵是用来衡量在给定的真实分布下,使用非真实分布所指定的策略消除系统的不确定性所需要付出的努力大小。
简单理解就是:交叉熵越低,非真实分布就越接近于真实分布,即摘要的信息量就越近于原文的信息量。
抽取式摘要(Extraction )
抽取式摘要是直接从原文中抽取一些句子组成摘要,其本质就是一个排序问题,我们给原文里每个句子打分,将分数高的句子摘出来
如果对摘要的长度有限制,可以对特别长的句子进行压缩,来节省空间
句子的权重计算就包含了3个方面:
- 词的权重
- 句子的位置信息
- 句子间的相似度
具体实现:
一、利用zhon,将原文中所有的句子切分出来
其中,zhon是一个Python的包,提供了中文文本处理中常用的常量
二、使用TF-IDF值,计算句子里词的权重
三、根据词的权重来计算句子的权重;计算位置权重,句子的相对位置比值;利用余弦相似度,计算句子相似度
四、3个权重值按照一定的系数详见,得到句子最终的权重
五、抽取原文的句子,生成摘要
权重系数是可以根据评测的反馈进行调整,以达到最优的效果。评测的方法可以使用ROUGE。
ROUGE(Recall-Oriented Understudy for Gisting Evaluation),是2003年提取的自动摘要系统评价方法,一直沿用至今,基于召回率的相似性度量方法。
通过将自动生成的摘要与一组参考摘要(通常是人工生成的)进行比较计算,得出相应的分值,以衡量自动生成的摘要与参考摘要之间的相似度。
** 生成式摘要(Abstraction)**
生成式摘要是通过抽象的语义表示,并使用语义推断和自然语言生成技术,来形成摘要,是一种监督学习的方式,需要大量的标注数据,比较难解决。
对语义性要求更高,但也是更加贴近自然语言,这里可以结合句法依存分析、语义依存分析。