├── Chapter_10 └── 第10章 基于深度学习的NLP算法.md ├── Chapter_9 └── 第9章 NLP中用到的机器学习算法.md ├── Chapter_2 └── 第2章 NLP前置技术解析.md ├── Chapter_8 └── 第8章 实战电影评论情感分析.md ├── Chapter_1 └── 第1章 NLP基础.md ├── README.md ├── Chapter_7 └── 第7章 文本向量化.md ├── Chapter_5 └── 第5章 关键词提取算法.md ├── Chapter_4 └── 第4章 词性标注与命名实体识别.md ├── Chapter_6 └── 第6章 句法分析.md └── Chapter_3 └── 第3章 中文分词技术.md /Chapter_10/第10章 基于深度学习的NLP算法.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter_9/第9章 NLP中用到的机器学习算法.md: -------------------------------------------------------------------------------- 1 | # 大纲 2 | 3 | - 机器学习的一些基本概念:有/无监督学习、半监督学习、回归、降维等 4 | - 机器学习常用分类算法:朴素贝叶斯、支持向量机、逻辑回归等 5 | - 机器学习的聚类方法:k-means算法 6 | - 机器学习的应用 7 | 8 | --- 9 | 10 | # 9.1 简介 11 | 12 | - 机器学习训练的要素 13 | 14 | - 数据 15 | - 转换数据的模型 16 | - 衡量模型好坏的损失函数 17 | - 调整模型权重以最小化损失函数的算法 18 | 19 | - 机器学习中最重要的四类问题(按学习结果) 20 | 21 | - 预测(Prediction):用回归(Regression,Arima)等模型; 22 | - 聚类(Clustering):如K-means方法; 23 | - 分类(Classification):支持向量机(Support Vector Machine,SVM)、逻辑回归(Logistic Regression); 24 | - 降维(Dimensional reduction):主成分分析法(Principal Component Analysis,即纯矩阵运算); 25 | 26 | - 按学习方法分 27 | 28 | - 监督学习(Supervised Learning):给定输入$x$,如何通过在标注输入和输出的数据上训练模型而预测输出$y$; 29 | 30 | ![监督学习框架](https://i.loli.net/2019/09/02/gAG3jl1HqFVnMdy.png) 31 | 主要是先准备训练数据,然后抽取所需特征形成特征向量(Feature Vectors),将这些特征连同对应标记(label)一起给学习算法,训练出一个预测模型(Predictive Model),然后采用同样的特征提取方法对新测试数据进行特征提取,然后使用预测模型对将来的数据进行预测; 32 | 33 | - 无监督学习(Un-supervised Learning) 34 | - 半监督学习(Semi-supervised Learning) 35 | - 增强学习(Reinforced Learning) 36 | 37 | --- 38 | 39 | # 9.2 几种常用机器学习方法 40 | 41 | - 文本分类 42 | 43 | 大致分为以下步骤: 44 | 45 | 1. 定义阶段:定义数据及分类体系,具体分为哪些类别,需要哪些数据; 46 | 2. 数据预处理:对文档分词、去停用词等; 47 | 3. 数据提取特征:对文档矩阵降维,提取训练集中最有用的特征; 48 | 4. 模型训练阶段:选择具体分类模型及算法,训练文本分类器; 49 | 5. 评测阶段:测试集上测试并评价分类器性能; 50 | 6. 应用阶段:应用性能最高的分类模型对分类文档进行分类; 51 | 52 | - 特征提取 53 | 54 | - Bag-of-words:最原始的特征集,一个单词/分词即为一个特征; 55 | - 统计特征:Term frequency(TF)、Inverse document frequency(IDF); 56 | - N-Gram:考虑词汇顺序的模型,即N阶Markov链,每个样本转移为转移概率矩阵; 57 | 58 | - 序列学习 59 | 60 | - 语音识别 61 | - 文本转语音 62 | - 机器翻译 63 | 64 | --- 65 | 66 | # 9.3 分类器方法 67 | 68 | - 朴素贝叶斯 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Chapter_2/第2章 NLP前置技术解析.md: -------------------------------------------------------------------------------- 1 | # 大纲 2 | 3 | - 选择Python作为自然语言开发语言的理由 4 | 5 | - 安装与使用Anaconda 6 | 7 | - 正则表达式 8 | 9 | - Numpy 10 | 11 | --- 12 | 13 | # 2.1 搭建Python开发环境 14 | 15 | 16 | - Python优势: 17 | 18 | 1. 丰富的自然语言处理库; 19 | 2. 编程语法简单易理解; 20 | 3. 许多数据科学相关的库; 21 | 22 | - Anaconda 23 | 24 | 安装以及简单实用教程见[Anaconda简单实用手册](https://blog.csdn.net/github_39655029/article/details/85238899)或[廖雪峰的Python教程之正则表达式教程](https://www.liaoxuefeng.com/wiki/1016959663602400/1017639890281664); 25 | 26 | --- 27 | 28 | # 2.2 正则表达式在NLP中的基本应用 29 | 30 | 书中知识较为简单,想要深入学习请参考相关教程[菜鸟教程之正则表达式](https://www.runoob.com/regexp/regexp-syntax.html) 31 | 32 | --- 33 | 34 | # 2.3 Numpy使用详解 35 | 36 | - 主要功能 37 | 38 | - ndarray,一个具有向量算数运算和复杂广播能力的多维数组对象; 39 | - 用于对数组数据进行快速运算的标准数学函数; 40 | - 用于读写磁盘数据的工具以及用于操作内存映射文件的工具; 41 | - 线性函数、傅里叶变换和随机数操作; 42 | - 用于集成C/C++和Fortran代码的工具; 43 | 44 | - 相关教程 45 | 46 | - [Numpy参考手册](https://www.numpy.org.cn/reference/index.html) 47 | - [CS231n课程笔记翻译:Python Numpy教程](https://zhuanlan.zhihu.com/p/20878530) 48 | 49 | - 简单使用 50 | 51 | ```python 52 | 53 | #--*--coding:utf-8--*-- 54 | 55 | import numpy as np 56 | 57 | # 直接导入向量 58 | vector = np.array([1,2,3,4]) 59 | # 导入矩阵 60 | matrix = np.array([[1,'Duncan'],[2,'Manu'],[3,'Paker'],[4,'Green']]) 61 | # 自动架构一个多行多列的array对象 62 | a = np.arange(15).reshape(3,5) 63 | # 获取Numpy中数组维度 64 | print(a.shape) 65 | # 获取本地数据 66 | file = np.genfromtxt('./data/demo.txt',delimiter=',') 67 | print(file) 68 | # 正确读取数据 69 | file_new = np.genfromtxt('./data/demo.txt',dtype = 'U75',skip_header=1,delimiter=',') 70 | print(new_file) 71 | # 索引 72 | matrix_new = np.array([[1, 2, 3],[40, 50, 60]]) 73 | print(matrix[1, 2]) 74 | # 数组比较 75 | m = (matrix_new == 10) 76 | print(m) 77 | # 数据类型转换 78 | vector = numpy.array(['1','2','3']) 79 | vector = vector.astype(float) 80 | ``` 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Chapter_8/第8章 实战电影评论情感分析.md: -------------------------------------------------------------------------------- 1 | # 大纲 2 | 3 | - 对舆情数据进行舆情分析 4 | - 分类算法应用 5 | - 初步了解深度学习方法RNN 6 | - 实战使用RNN变种-LSTM 7 | 8 | --- 9 | 10 | # 8.1 情感分析的应用 11 | 12 | - 电子商务 13 | - 舆情分析 14 | - 市场呼声 15 | - 消费者呼声 16 | 17 | --- 18 | 19 | # 8.2 情感分析的基本方法 20 | 21 | - 分析方法分类 22 | 23 | - 词法分析 24 | - 基于机器学习的分析 25 | - 混合分析 26 | 27 | - 词法分析 28 | 29 | 运用预标记词汇组成的字典,使用词法分析器将输入文本转换为单词序列,将每个新的单词与字典中的词汇进行匹配,若有积极匹配,则对输入文本的分数总池进行加分,若是消极匹配,则输入文本总分减少。但是存在一个不足:其性能(时间复杂度和准确率)随着字典大小(词汇数量)增加而下降。流程如下图; 30 | 31 | ![处理方法流程](https://i.loli.net/2019/08/31/lc8WpITCwav6qZi.png) 32 | 33 | - 机器学习方法 34 | 35 | 主要使用监督学习方法,分为:数据收集、预处理、训练分类三阶段,其关键是选择合适的特征,从而觉得分类器的准确率。主要面临:分类器设计、训练数据的获取、对未见过的短语的正确解释等挑战; 36 | 37 | --- 38 | 39 | # 8.3 实战电影评论情感分析 40 | 41 | - CNN 42 | 43 | ![CNN结构](https://i.loli.net/2019/08/31/MHgItn4pRsLiUB5.png) 44 | 45 | 利用卷积层处理词向量序列,生成多通道特征图,对特征图采用时间维度上的最大池化操作来得到与此卷积核对应的整句话的特征,最后将所有卷积核得到的特征拼接起来即为文本的定长向量表示; 46 | 47 | - RNN 48 | 49 | ![句子示意图](https://i.loli.net/2019/08/31/VPE9qSTeDGArzgi.png) 50 | 51 | RNN按时间顺序展开,在$t$时刻,网络读入第$t$个输入$x_t$,以及前一时刻状态值$h_{t-1}$(向量表示,$h_0$表示初始化为0的向量),从而计算出本时刻隐藏层的状态值$h_t$,若函数表示为$f$,则公式表示为: 52 | 53 | $$h_t=f(x_t,h_{t-1})=\sigma(W_{xh}x_t+W_{hh}h_{t-1}+b_h)$$ 54 | 55 | 其中$W_{xh}$是输入层到隐藏层的矩阵参数,$W_{hh}$为隐藏层到隐藏层的矩阵参数,$b_h$为隐藏层偏置参数。RNN示意图如下,隐藏层的状态向量被送入一个Softmax分类器,然后判断其情感; 56 | 57 | ![RNN示意图](https://i.loli.net/2019/08/31/sI14tTz5rkNegyh.png) 58 | 59 | - LSTM 60 | 61 | 保留了文本中的长期依赖信息,通过对循环层的刻意设计避免了长期依赖和梯度消失问题。输入单元输入数据$x(t)$,隐藏层输出$h(t)$,在这些单元中,隐藏层表达复杂,主要分为4个部分:输入门$i$、输出门$o$、遗忘门$f$、记忆控制器$c$,将LSTM表示函数记为$F$,$h_t=F(x_t,h_{t-1})$; 62 | 63 | ![title](https://i.loli.net/2019/09/02/ZfBtdHp3c1P7qvg.png) 64 | 65 | 其中$W$及$b$是模型参数,$tanh$是双曲正切函数; 66 | 67 | ![LSTM cell单元图](https://i.loli.net/2019/09/02/sxlnLJ4TgSzKfkc.png) 68 | 69 | - 情感分析任务步骤 70 | 71 | - 训练或载入一个词向量生成模型; 72 | - 创建一个用于训练集的ID矩阵; 73 | - 创建LSTM计算单元; 74 | - 训练; 75 | - 测试; 76 | -------------------------------------------------------------------------------- /Chapter_1/第1章 NLP基础.md: -------------------------------------------------------------------------------- 1 | # 大纲 2 | 3 | - NLP基础概念 4 | 5 | - NLP的发展与应用 6 | 7 | - NLP常用术语以及扩展介绍 8 | 9 | --- 10 | 11 | # 1.1 什么是NLP 12 | 13 | - 基本分类 14 | 15 | ![NLP基本分类](https://i.loli.net/2019/08/26/9Lmo7Up4OQXg1Hd.png) 16 | 17 | - 自然语言生成(Natural Language Generation,NLG) 18 | 19 | 指从结构化数据中以读取的方式自动生成文本,主要包括三个阶段: 20 | 21 | - 文本规划:完成结构化数据中的基础内容规划; 22 | - 语句规划:从结构化数据中组合语句来表达信息流; 23 | - 实现:产生语法通顺的语句来表达文本; 24 | 25 | - 研究任务 26 | 27 | - 机器翻译 28 | - 情感分析 29 | - 智能问答 30 | - 文摘生成 31 | - 文本分类 32 | - 舆论分析 33 | - 知识图谱 34 | 35 | --- 36 | 37 | # 1.2 NLP的发展历程 38 | 39 | - 萌芽期(1956年以前) 40 | 41 | 贝叶斯方法、隐马尔可夫、最大熵、支持向量机……,主流仍为基于规则的理性主义方法; 42 | 43 | - 快速发展期(1980~1999年) 44 | 45 | 基于统计、基于实例和基于规则的语料库技术在这一时期蓬勃发展; 46 | 47 | - 突飞猛进期(2000年至今) 48 | 49 | 神经网络与深度学习; 50 | 51 | --- 52 | 53 | # 1.3 NLP相关知识的构成 54 | 55 | - 基本术语 56 | 57 | - 分词(segment) 58 | - 词性标注(part-of-speech tagging) 59 | - 命名实体识别(NER,Named Entity Recognition) 60 | 61 | 指从文本中识别具有特定类标的实体(常为名词),如人名、地名、机构名、专有名词等; 62 | 63 | - 句法分析(syntax parsing) 64 | 65 | 目的是解析句子中各个成分的依赖关系; 66 | 67 | - 指代消解(anaphora resolution) 68 | - 情感识别(emotion recognition) 69 | - 纠错(correction) 70 | - 问答系统(QA system) 71 | - 知识结构 72 | 73 | NLP是一门跨学科科学,体系化与特殊化并存,其知识体系如下: 74 | 75 | - **句法语义分析**:针对目标句子,进行各种句法分析; 76 | - **关键词抽取**:抽取目标文本中的主要信息; 77 | - **文本挖掘**:主要包含对文本的聚类、分类、信息抽取、摘要、情感分析及对挖掘的信息和知识的可视化、交互式的呈现界面; 78 | - **信息检索**:对大规模的文档进行索引; 79 | - **机器翻译**:将输入的源语言文本通过自动化翻译转化为另一种语言的文本; 80 | - **问答系统**:针对某个自然语言表达的问题,由问答系统给出一个精确答案; 81 | - **对话系统**:系统通过多回合对话,与用户进行聊天、问答、完成某项任务; 82 | 83 | ![知识结构图示](https://i.loli.net/2019/08/26/LBWhK5q8V4Zd6JF.png) 84 | 85 | --- 86 | 87 | # 1.4 语料库 88 | 89 | - [中文维基百科](https://dumps.wikimedia.org/zhwiki) 90 | 91 | - [搜狗新闻语料库](https://download.labs.sogou.com/resource/ca.php) 92 | 93 | - [IMDB情感分析语料库](https://www.kaggle.com/tmdb/tmdb-movie-metadata) 94 | 95 | - [fastText词向量](https://fasttext.cc/docs/en/pretrained-vectors.html) 96 | 97 | - [维基可比语料](https://linguatools.org/tools/corpora/wikipedia-comparable-corpora/) 98 | 99 | --- 100 | 101 | # 1.5 探究NLP的几个层面 102 | 103 | - 第一层面:词法分析 104 | 105 | - 分词 106 | 107 | - 词性标注 108 | 109 | 目的是为每个词赋予一个类别; 110 | 111 | - 第二层面:句法分析 112 | 113 | 对输入的文本以句子为单位,进行分析从而得到句子的句法结构的处理过程; 114 | 115 | - 第三层面:语义分析 116 | 117 | 语义角色标注(semantic role labeling)是当前较为成熟的浅层语义分析技术; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python_nlp_practice 2 | 3 | 《Python自然语言处理实战:核心技术与算法(涂铭)》笔记。 4 | 5 | The notes for Natural Language Processing:Core Technology and Algorithm with Python. 6 | 7 | ## 目录:Context 8 | 9 | | 章节 | 链接 | 10 | | :----: | :----------------------------------------------------------- | 11 | | 第1章 | [NLP基础](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_1/%E7%AC%AC1%E7%AB%A0%20NLP%E5%9F%BA%E7%A1%80.md) | 12 | | 第2章 | [NLP前置技术解析](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_2/%E7%AC%AC2%E7%AB%A0%20NLP%E5%89%8D%E7%BD%AE%E6%8A%80%E6%9C%AF%E8%A7%A3%E6%9E%90.md) | 13 | | 第3章 | [中文分词技术](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_3/%E7%AC%AC3%E7%AB%A0%20%E4%B8%AD%E6%96%87%E5%88%86%E8%AF%8D%E6%8A%80%E6%9C%AF.md) | 14 | | 第4章 | [词性标注与命名实体识别](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_4/%E7%AC%AC4%E7%AB%A0%20%E8%AF%8D%E6%80%A7%E6%A0%87%E6%B3%A8%E4%B8%8E%E5%91%BD%E5%90%8D%E5%AE%9E%E4%BD%93%E8%AF%86%E5%88%AB.md) | 15 | | 第5章 | [关键词提取算法](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_5/%E7%AC%AC5%E7%AB%A0%20%E5%85%B3%E9%94%AE%E8%AF%8D%E6%8F%90%E5%8F%96%E7%AE%97%E6%B3%95.md) | 16 | | 第6章 | [句法分析](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_6/%E7%AC%AC6%E7%AB%A0%20%E5%8F%A5%E6%B3%95%E5%88%86%E6%9E%90.md) | 17 | | 第7章 | [文本向量化](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_7/%E7%AC%AC7%E7%AB%A0%20%E6%96%87%E6%9C%AC%E5%90%91%E9%87%8F%E5%8C%96.md) | 18 | | 第8章 | [情感分析技术](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_8/%E7%AC%AC8%E7%AB%A0%20%E5%AE%9E%E6%88%98%E7%94%B5%E5%BD%B1%E8%AF%84%E8%AE%BA%E6%83%85%E6%84%9F%E5%88%86%E6%9E%90.md) | 19 | | 第9章 | [NLP中用到的机器学习算法](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_9/%E7%AC%AC9%E7%AB%A0%20NLP%E4%B8%AD%E7%94%A8%E5%88%B0%E7%9A%84%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95.md) | 20 | | 第10章 | [基于深度学习的NLP算法](https://github.com/cunyu1943/python_nlp_practice/blob/master/Chapter_10/%E7%AC%AC10%E7%AB%A0%20%E5%9F%BA%E4%BA%8E%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E7%9A%84NLP%E7%AE%97%E6%B3%95.md) | 21 | 22 | ## 请小编喝咖啡 23 | 24 | | 微信 | 支付宝 | 25 | | :----------------------------------------------------------: | :----------------------------------------------------------: | 26 | | ![](https://raw.githubusercontent.com/cunyu1943/image-hosting-for-blog/master/img/20191112210029.png) | ![](https://raw.githubusercontent.com/cunyu1943/image-hosting-for-blog/master/img/20191112205944.jpg) | 27 | 28 | ## 联系小编 29 | 30 | | 微信 | 微信公众号 | 31 | | :----------------------------------------------------: | :----------------------------------------------------: | 32 | | ![](https://i.loli.net/2019/10/03/gzn7Ps24tRydu9S.jpg) | ![](https://i.loli.net/2019/10/03/G6tUxN48WBQbTvH.jpg) | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Chapter_7/第7章 文本向量化.md: -------------------------------------------------------------------------------- 1 | # 大纲 2 | 3 | - 文本向量化常用算法介绍,word2vec及doc2vec 4 | - 向量化方法的模型训练和使用 5 | 6 | --- 7 | 8 | # 7.1 文本向量化概述 9 | 10 | 即将文本表示为一系列能表达文本语义的向量; 11 | 12 | --- 13 | 14 | # 7.2 向量化算法word2vec 15 | 16 | - 词袋(Bag of Word)模型:最早的以词语为基本处理单元的文本向量化方法; 17 | 18 | - 词袋模型存在的问题: 19 | 20 | - 维度灾难 21 | - 无法保留词序信息 22 | - 存在语义鸿沟问题 23 | 24 | - 神经网络语言模型(NNLM) 25 | 26 | ![NNLM语言模型](https://i.loli.net/2019/08/30/16CTtBQzNcGg9Ek.png) 27 | 28 | 大致操作步骤:从语料库中收集一系列长度为$n$的文本序列$w_{i-(n-1)},…,w_{i-1},w_i$,设这个长度为$n$的文本序列组成的集合为$D$,则NNML的目标函数定义为: 29 | 30 | $$\sum _DP(w_i|w_{i-(n-1)},…,w_{i-1})$$ 31 | 32 | 即:在输入词序列为$w_{i-(n-1)},…,w_{i-1}$的情况下,计算目标词$w_i$的概率; 33 | 34 | 在上述经典三层前馈神经网络结构中:为解决词袋模型数据稀疏问题,输入层的输入为低纬度的、紧密的词向量,将词序列$w_{i-(n-1)},…,w_{i-1}$中每个词向量按顺序进行拼接,即: 35 | 36 | $$x=[v(w_{i-(n-1)});…;v(w_{i-2});v(w_{i-1})]$$ 37 | 38 | 接下来,$x$经隐藏层得到$h$,再将$h$接入输入层从而得到最后的输出变量$y$,其中: 39 | 40 | $$h=tanh(b+Hx)$$ 41 | 42 | $$y=b+Uh$$ 43 | 44 | 其中$H$是输入层到隐藏层的权重矩阵,维度为$|h|\times(n-1)|e|$;$U$是隐藏层到输出层的权重矩阵,维度为$|V|\times |h|$,其中$|V|$表示词表大小,$b$则是模型中的偏置项;为保证输出$y(w)$的表示概率值,需对输出层进行归一化操作,一般是加入$softmax$码数,将$y$转化成对应概率值: 45 | 46 | $$P(w_i|w_{i-(n-1)}…,w_{i-1})=\frac {exp(y(w_i))}{\sum _{k=1}^{|V|}exp(y(w_k))}$$ 47 | 48 | 因为输出是在上下文词序列出现的情况下,下一个词的概率,所以语料库$D$中最大化$y(w_i)$即为$NNLM$模型的目标函数: 49 | 50 | $$\sum _{w_{i-(n-1);i in D}}log P(w_i|w_{i-(n-1)},…,w_{i-1})$$ 51 | 52 | 一般使用随机梯度下降法对模型进行训练,对于每个$batch$,随机从语料库中抽取若干样本进行训练,其迭代公式为: 53 | 54 | $$\theta:\theta+\alpha \frac{\partial logP(w_i|w_{i-(n-1)},…,w_{i-1})}{\partial \theta}$$ 55 | 56 | $\alpha$为学习率,$\theta$包括模型中设计所有参数,包括$NNLM$模型中的权重、偏置以及输入词向量; 57 | 58 | - C&W模型 59 | 60 | ![C&W模型结构图](https://i.loli.net/2019/08/31/V12SxoGnalDNwke.png) 61 | 62 | $C&W$模型未采用语言模型的方式求解词语上下文的条件概率,而是直接对$n$元短语打分,其核心机理为:若$n$元短语在语料中出现过,则模型给该短语打一个高分,若未出现的短语,则赋予一个较低评分,其目标函数为: 63 | 64 | $$\sum _{(w,c)\in D} \sum_{w^` \in V}max(0,1-score(w,c)+score(w^`,c))$$ 65 | 66 | $(w,c)$是从语料中抽取的$n$元短语,为保证上下文词数一致性$n$应该为奇数,$w$是目标词,$c$表示目标词上下文语境,$w^`$是词典中随机抽取的词; 67 | 68 | - CBOW模型 69 | 70 | ![CBOW模型结构图](https://i.loli.net/2019/08/31/iyZ941D68EKNgrU.png) 71 | 72 | 根据上下文来预测当前词语的概率,使用文本中间词作为目标词,同时去除隐藏层从而提升运算速率,其输入层激吻语义上下文的表示; 73 | 74 | 对目标词的条件概率公式如下: 75 | 76 | $$P(w|c)=\frac {exp(e^`(w)^Tx)}{\sum _{w^` \in V} exp(e^`(w^`)^Tx)}$$ 77 | 78 | 其目标函数类似于$NNLM$模型,为最大化式: 79 | 80 | $$\sum _{(w,c)\in D}logP(w,c)$$ 81 | 82 | - Skim-gram模型 83 | 84 | ![SG模型结构图](https://i.loli.net/2019/08/31/UNFVnfweLiOtHI5.png) 85 | 86 | 根据当前词语来预测上下文概率,从目标词$w$的上下文中选择一个词,然后将其词向量组成上下文的表示,模型目标函数为: 87 | 88 | $$max(\sum_{(w,c)\in D} \sum _{w_j \in c}log P(w|w_j))$$ 89 | 90 | --- 91 | 92 | # 7.3 向量化算法doc2vec/str2vec 93 | 94 | doc2vec包括DM(Distributed Memory)和DBOW(Distributed Bag of Words),DM模型视图预测给定上下文(不仅包含单词,还包含相应段落)求某单词出现的概率,而DBOW则在仅给定段落向量的情况下预测段落中一组随机单词的概率。总体而言,doc2vec是word2vec的升级,doc2vec不仅提取了文本的语义信息,还提取了文本的语序信息; 95 | 96 | ![CBOW模型例子](https://i.loli.net/2019/08/31/fQyoZWm3SrEiqNv.png) 97 | 98 | ![DM模型示意图](https://i.loli.net/2019/08/31/6z5RF91YfhGwCHI.png) 99 | 100 | ![DBOW模型示意图](https://i.loli.net/2019/08/31/1rUfsOilwMjdPK5.png) 101 | 102 | --- 103 | 104 | # 7.4 将网页文本向量化 -------------------------------------------------------------------------------- /Chapter_5/第5章 关键词提取算法.md: -------------------------------------------------------------------------------- 1 | # 大纲 2 | 3 | - 关键词提取技术介绍 4 | - 常用的关键词提取算法详解 5 | - 文本关键词提取实战 6 | 7 | --- 8 | 9 | # 5.1 关键词提取技术概述 10 | 11 | - 有监督 12 | 13 | 主要通过分类的方式进行,通过构建一个丰富和完善的词表,然后通过判断每个文档与词表中每个文档与词表中每个词的匹配程度,以类似打标签的方式,从而达到关键词提取的效果。能够获得较高精度,但是需要大批量的标注数据,人工成本较高; 14 | 15 | - 无监督 16 | 17 | 不需人工生成、维护的词表,也不需要人工标注语料辅助进行训练,主要有TF-IDF算法、TextRank算法和主题模型算法(LSA、LSI、LDA等); 18 | 19 | --- 20 | 21 | # 5.2 关键词提取算法TF-IDF 22 | 23 | - TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频次算法):基于统计的计算方法,常用于评估一个文档集中一个词对某份文档的重要程度。TF算法统计一个词在一篇文档中出现的频次,**基本思想**为:一个词在文档中出现的词数越多,则对文档的表达能力也越强。IDF算法统计一个词在文档集中的多少个文档中出现,**基本思想**为:若一个词在越少的文档中出现,则对文档的区分能力越强; 24 | 25 | $$tf_{ij}=\frac{n_{ij}}{\sum _k n_{kj}}$$ 26 | 27 | $$idf_i=log(\frac{|D|}{1+|D_i|})$$ 28 | 29 | $$tf-idf(i,j) = tf_{ij} \times idf_i = \frac{n_{ij}}{\sum _k n_{kj}} \times log(\frac{|D|}{1+|D_i|})$$ 30 | 31 | $|D|$为文档集中总文档树,$|D_i|$是文档集中出现词$i$的文档数量,而分母$+1$则是采用拉普拉斯平滑,避免有部分新词在语料库中未出现而导致分母为零的情况; 32 | 33 | --- 34 | 35 | # 5.3 TextRank算法 36 | 37 | - TextRank算法可以脱离语料库,仅对单篇文档进行分析从而提取该文档的关键词,最早用于文档自动摘要,基于句子维度的分析,利用TextRank对每个句子进行打分,挑出分数最高的$n$个句子作为文档的关键句,从而达到自动摘要的效果,基本思想源于PageRank算法; 38 | 39 | - PageRank 40 | 41 | ![PageRank算法计算示意图](https://i.loli.net/2019/08/29/sNQWMdkpRfTcSwH.png) 42 | 43 | $$S(V_i)=(1-d)+d\times \sum_{j \in ln(V_j)}(\frac {1}{|Out(V_j)|}\times S(V_j))$$ 44 | 45 | 1. 基本思想 46 | 47 | - 链接数量 48 | - 链接质量 49 | 50 | - TextRank 51 | 52 | $$WS(V_i)=(1-d)+d \times \sum_{V_j \in ln(V_i)}(\frac {w_{ji}}{\sum_{V_{k \in Out(V_j)_{w_{jk}}}}}\times WS(V_j))$$ 53 | 54 | PageRank是有向无权图,而TextRank进行自动摘要则是有权图。当TextRank应用到关键词提取时,与自动摘要中主要有两点不同: 55 | 56 | 1. 词与词之间的关联无权重 57 | 2. 每个词不是与文档中所有词都有链接 58 | 59 | 由于第1点,故TextRank中的分数计算公式就变为PageRank一直,通过将得分平均贡献给每个链接的词: 60 | 61 | $$WS(V_i)=(1-d)+d \times \sum_{j \in ln(V_i)}(\frac {1}{|Out(V_j)|}\times WS(V_j))$$ 62 | 63 | --- 64 | 65 | # 5.4 LSA/LSI/LDA算法 66 | 67 | - LSA/LSI算法 68 | 69 | - LSA(Latent Semantic Analysis,潜在语义分析)主要利用SVD(奇异值分解)的方法进行暴力破解,和LSI(Latent Semantic Index,潜在语义索引)通常被认为是同一种算法,只有应用场景略有不同; 70 | 71 | - LSA的主要步骤: 72 | 73 | 1. 使用BOW模型将每个文档表示为向量; 74 | 2. 将所有的文档词向量拼接构成词-文档矩阵($m\times n$); 75 | 3. 对词-文档矩阵进行SVD操作($[m \times r]\cdot[r\times r]\cdot[r\times n]$); 76 | 4. 根据SVD的结果,将词-文档矩阵进行奇异值分解到更低维度$k$($[m \times k]\cdot[k\times k]\cdot[k\times n],0$$ 79 | 80 | 上式为最大间隔马尔可夫网络判别函数,$\phi (x,y)$表示与$x$相对应的句法树$y$的特征向量,$w$表示特征权重。通过采用多个独立且可并行训练的二分类器,每个二分类器识别一个短语标记,通过组合这些分类器完成句法分析任务,同时并行方式训练也提升了速度; 81 | 82 | - 基于CRF的句法分析 83 | 84 | 相比于PCFG模型,主要不同在于概率计算方法和概率归一化的方式。CRF最大化的是句法树的条件概率值而非联合概率值,而且对概率进行归一化。也是一种判别式方法,需融合大量特征; 85 | 86 | - 基于移进-归约(Shift-Reduce Algorithm)的句法分析模型 87 | 88 | 一种自下而上的方法,从输入串开始逐步进行归约,直到文法的开始符号,类似于下推自动机的LR分析法,最基本的数据结构式堆栈,主要涉及以下4种操作(S:句法树根节点): 89 | 90 | - 移进:从句子左端将一个终结符一道栈顶; 91 | - 归约:根据规则,将栈顶的若干个字符替换为一个符号; 92 | - 接收:句子中所有词均移入栈中,栈中只剩一个符号$S$,从而判定分析成功,结束; 93 | - 拒绝:句子中所有词已进栈,栈中不止一个符号$S$,也就无法进行任何归约操作,导致分析失败; 94 | 95 | --- 96 | 97 | # 6.4 使用Stanford Parser的PCFG算法进行句法分析 98 | 99 | - Stanford Parser主要优点: 100 | 101 | - 既是一个高度优化的概率上下文无关文法和词汇化依存分析器,又是一个词汇化上下文无关文法分析器; 102 | - 以宾州树库作为分析器的训练数据,支持多语言; 103 | - 提供多样化的分析输出形式,出句法分析树输出外,还支持分词、词性标注、短语结构、依存句法等输出; 104 | - 内置分词、词性标注、基于自定义树库的分析器训练等辅助工作; 105 | - 支持多平台,并封装了多种语言接口; 106 | 107 | - [包下载链接](https://nlp.stanford.edu/software/lex-parser.shtml) 108 | 109 | - 基于PCFG的中文句法分析实战 110 | 111 | ```python 112 | 113 | #!/usr/bin/env python 114 | # -*- coding: utf-8 -*- 115 | # @version : 1.0 116 | # @Time : 2019-8-30 11:03 117 | # @Author : cunyu 118 | # @Email : cunyu1024@foxmail.com 119 | # @Site : https://cunyu1943.github.io 120 | # @File : pcfg_parser.py 121 | # @Software: PyCharm 122 | # @Desc : 使用Stanford Parser的PCFG算法进行句法分析 123 | 124 | import jieba 125 | from nltk.parse import stanford 126 | import os 127 | from nltk.tree import Tree 128 | 129 | if __name__ == '__main__': 130 | 131 | # 分词 132 | string = "中华人民共和国成立于1949年,至今已有70周年" 133 | seg_list = jieba.cut(string, cut_all=False, HMM=True) 134 | seg_str = ' '.join(seg_list) 135 | print(seg_str) 136 | 137 | # PCFG句法分析 138 | 139 | root = '/data/zhangliang/software/' 140 | 141 | parser_path = root + 'stanford/stanford-parser.jar' 142 | model_path = root + 'stanford/stanford-parser-3.9.2-models.jar' 143 | 144 | # 指定jdk路径 145 | if not os.environ.get('JAVA_HOME'): 146 | JAVA_HOME = '/data/zhangliang/software/Java' 147 | os.environ['JAVA_HOME'] = JAVA_HOME 148 | 149 | # PCFG模型路径 150 | pcfg_path = 'edu/stanford/nlp/models/lexparser/chinesePCFG.ser.gz' 151 | 152 | parser = stanford.StanfordParser(path_to_jar=parser_path, path_to_models_jar=model_path, model_path=pcfg_path) 153 | 154 | sentence = parser.raw_parse(seg_str) 155 | for line in sentence: 156 | print(line) 157 | 158 | ``` 159 | -------------------------------------------------------------------------------- /Chapter_3/第3章 中文分词技术.md: -------------------------------------------------------------------------------- 1 | # 大纲 2 | 3 | - 中文分词的概念与分类 4 | 5 | - 常用分词(规则分词、统计分词、混合分词)技术介绍 6 | 7 | - 开源中文分词工具-Jieba 8 | 9 | - 实战分词之高频词提取 10 | 11 | --- 12 | 13 | # 3.1 中文分词简介 14 | 15 | 1. 规则分词 16 | 17 | 最早兴起,主要通过人工设立词库,按照一定方式进行匹配切分,实现简单高效,但对新词难以处理; 18 | 19 | 2. 统计分词 20 | 21 | 能较好应对新词发现场景,但是太过于依赖于语料质量; 22 | 23 | 3. 混合分词 24 | 25 | 规则分词与统计分词的结合体; 26 | 27 | --- 28 | 29 | # 3.2 规则分词 30 | 31 | - 定义 32 | 33 | 一种机械分词方法,主要通过维护词典,切分语句时,将语句中的每个字符串与词表中的词逐一匹配,找到则切分,否则不切分; 34 | 35 | - 分类 36 | 37 | - 正向最大匹配法(Maximum Match Method,MM法) 38 | 39 | 1. 基本思想 40 | 41 | 假定分词词典中最长词有$i$个汉字字符,则用被处理文档的当前字符串中的前$i$个字作为匹配字段,查找字典; 42 | 43 | 2. 算法描述 44 | 45 | - 从左向右取待切分汉语句的$m$个字符作为匹配字段,$m$是机器词典中最长词条的字符数; 46 | - 查找机器词典并进行匹配。匹配成功则将匹配字段作为一个词切分出来,匹配失败则将匹配字段的最后一个字去掉,剩下的字符串作为新的匹配字段,进行再匹配,一直重复上述过程指导切分出所有词; 47 | 48 | - 逆向最大匹配法(Reverse Maximum Match Method,RMM法) 49 | 50 | 1. 基本原理 51 | 52 | 从被处理文档末端开始匹配扫描,每次取末端的$i$个字符作为匹配字段,匹配事变则去掉匹配字段最前一个字,继续匹配; 53 | 54 | - 双向最大匹配(Bi-direction Matching Method) 55 | 56 | 1. 基本原理 57 | 58 | 将正向最大匹配法和逆向最大匹配法得到的分词结果进行比较,庵后按照最大匹配原则,选取词数切分最少的作为结果; 59 | 60 | - 相关代码 61 | 62 | 1. 正向最大匹配 63 | 64 | ```python 65 | 66 | #!/usr/bin/env python 67 | # -*- coding: utf-8 -*- 68 | # @version : 1.0 69 | # @Time : 2019-8-25 15:27 70 | # @Author : cunyu 71 | # @Email : cunyu1024@foxmail.com 72 | # @Site : https://cunyu1943.github.io 73 | # @File : mm.py 74 | # @Software: PyCharm 75 | # @Desc : 正向最大匹配分词 76 | 77 | train_data = './data/train.txt' # 训练语料 78 | test_data = './data/test.txt' # 测试语料 79 | result_data = './data/test_sc_zhengxiang.txt' # 生成结果 80 | 81 | 82 | def get_dic(train_data): # 读取文本返回列表 83 | with open(train_data, 'r', encoding='utf-8', ) as f: 84 | try: 85 | file_content = f.read().split() 86 | finally: 87 | f.close() 88 | chars = list(set(file_content)) 89 | return chars 90 | 91 | 92 | def MM(test_data, result_data, dic): 93 | # 词的最大长度 94 | max_length = 5 95 | 96 | h = open(result_data, 'w', encoding='utf-8', ) 97 | with open(test_data, 'r', encoding='utf-8', ) as f: 98 | lines = f.readlines() 99 | 100 | for line in lines: # 分别对每行进行正向最大匹配处理 101 | max_length = 5 102 | my_list = [] 103 | len_hang = len(line) 104 | while len_hang > 0: 105 | tryWord = line[0:max_length] 106 | while tryWord not in dic: 107 | if len(tryWord) == 1: 108 | break 109 | tryWord = tryWord[0:len(tryWord) - 1] 110 | my_list.append(tryWord) 111 | line = line[len(tryWord):] 112 | len_hang = len(line) 113 | 114 | for t in my_list: # 将分词结果写入生成文件 115 | if t == '\n': 116 | h.write('\n') 117 | else: 118 | print(t) 119 | h.write(t + " ") 120 | h.close() 121 | 122 | 123 | if __name__ == '__main__': 124 | print('读入词典') 125 | dic = get_dic(train_data) 126 | print('开始匹配') 127 | MM(test_data, result_data, dic) 128 | 129 | ``` 130 | 131 | 2. 逆向最大匹配 132 | 133 | ```python 134 | 135 | #!/usr/bin/env python 136 | # -*- coding: utf-8 -*- 137 | # @version : 1.0 138 | # @Time : 2019-8-25 15:36 139 | # @Author : cunyu 140 | # @Email : cunyu1024@foxmail.com 141 | # @Site : https://cunyu1943.github.io 142 | # @File : rmm.py 143 | # @Software: PyCharm 144 | # @Desc : 逆向最大匹配法 145 | 146 | train_data = './data/train.txt' 147 | test_data = './data/test.txt' 148 | result_data = './data/test_sc.txt' 149 | 150 | 151 | def get_dic(train_data): 152 | with open(train_data, 'r', encoding='utf-8', ) as f: 153 | try: 154 | file_content = f.read().split() 155 | finally: 156 | f.close() 157 | chars = list(set(file_content)) 158 | return chars 159 | 160 | def RMM(test_data,result_data,dic): 161 | max_length = 5 162 | 163 | h = open(result_data, 'w', encoding='utf-8', ) 164 | with open(test_data, 'r', encoding='utf-8', ) as f: 165 | lines = f.readlines() 166 | 167 | for line in lines: 168 | my_stack = [] 169 | len_hang = len(line) 170 | while len_hang > 0: 171 | tryWord = line[-max_length:] 172 | while tryWord not in dic: 173 | if len(tryWord) == 1: 174 | break 175 | tryWord = tryWord[1:] 176 | my_stack.append(tryWord) 177 | line = line[0:len(line) - len(tryWord)] 178 | len_hang = len(line) 179 | 180 | while len(my_stack): 181 | t = my_stack.pop() 182 | if t == '\n': 183 | h.write('\n') 184 | else: 185 | print(t) 186 | h.write(t + " ") 187 | 188 | h.close() 189 | 190 | 191 | if __name__ == '__main__': 192 | print('获取字典') 193 | dic = get_dic(train_data) 194 | print('开始匹配……') 195 | RMM(test_data,result_data,dic) 196 | ``` 197 | 198 | --- 199 | 200 | # 3.3 统计分词 201 | 202 | - 主要操作 203 | 204 | - 建立统计语言模型; 205 | - 对句子进行单词划分,然后对划分结果进行概率计算,获得概率最大额分词方式,常用统计学习算法有隐含马尔可夫(HMM)、条件随机场(CRF)等; 206 | 207 | - n元条件概率 208 | 209 | $$P(w_i|w_{i-(n-1)},…,w_{i-1})=\frac{count(w_{i-(n-1)},…,w_{i-1},w_i)}{count(w_{i-(n-1)},…,w_{i-1})}$$ 210 | 211 | 其中,$count(w_{i-(n-1)},…,w_{i-1})$表示词$w_{i-(n-1)},…,w_{i-1}$在语料库中出现的总次数; 212 | 213 | - HMM模型 214 | 215 | 将分词作为字在字串中的序列标注任务来实现。基本思路:每个字在构造一个特定的词语时都占据着一个确定的构词位置(即词位),规定每个字最多有四个构词位置:B(词首)、M(词中)、E(词尾)、S(单独成词); 216 | 217 | 1. 数学理论 218 | 219 | 假设用$\lambda=\lambda _1 \lambda_2 …\lambda_n$代表输入的句子,$n$表示句子长度,$\lambda_i$表示字,$o=o_1o_2…o_n$表示输出的标签,则理想输出为: 220 | 221 | $$max = maxP(o=o_1o_2…o_n|\lambda=\lambda _1 \lambda_2 …\lambda_n)=P(o_1|\lambda_1)P(o_2|\lambda_2)…P(o_n|\lambda_n)$$ 222 | 223 | 在这个算法中,求解结果的常用方法是Veterbi算法,这是一种动态规划算法,**核心**是:如果最终的最优路径经过某个节点$o_i$,则从初始节点到$o_{i-1}$点的路径必然也是一个最优路径,因为每个节点$o_i$只会影响前后两个$P(o_{i-1}|o_i)$和$P(o_i|o_{i+1})$; 224 | 225 | 2. Python实现 226 | 227 | ```python 228 | #!/usr/bin/env python 229 | # -*- coding: utf-8 -*- 230 | # @version : 1.0 231 | # @Time : 2019-8-27 15:42 232 | # @Author : cunyu 233 | # @Email : cunyu1024@foxmail.com 234 | # @Site : https://cunyu1943.github.io 235 | # @File : HMM_model.py 236 | # @Software: PyCharm 237 | # @Desc : HMM模型分词 238 | 239 | import os 240 | import pickle 241 | 242 | 243 | class HMM(object): 244 | def __init__(self): 245 | import os 246 | 247 | # 主要是用于存取算法中间结果,不用每次都训练模型 248 | self.model_file = './data/models/hmm_model.pkl' 249 | 250 | # 状态值集合 251 | self.state_list = ['B', 'M', 'E', 'S'] 252 | # 参数加载,用于判断是否需要重新加载model_file 253 | self.load_para = False 254 | 255 | # 用于加载已计算的中间结果,当需要重新训练时,需初始化清空结果 256 | def try_load_model(self, trained): 257 | if trained: 258 | import pickle 259 | with open(self.model_file, 'rb') as f: 260 | self.A_dic = pickle.load(f) 261 | self.B_dic = pickle.load(f) 262 | self.Pi_dic = pickle.load(f) 263 | self.load_para = True 264 | 265 | else: 266 | # 状态转移概率(状态->状态的条件概率) 267 | self.A_dic = {} 268 | # 发射概率(状态->词语的条件概率) 269 | self.B_dic = {} 270 | # 状态的初始概率 271 | self.Pi_dic = {} 272 | self.load_para = False 273 | 274 | # 计算转移概率、发射概率以及初始概率 275 | def train(self, path): 276 | 277 | # 重置几个概率矩阵 278 | self.try_load_model(False) 279 | 280 | # 统计状态出现次数,求p(o) 281 | Count_dic = {} 282 | 283 | # 初始化参数 284 | def init_parameters(): 285 | for state in self.state_list: 286 | self.A_dic[state] = {s: 0.0 for s in self.state_list} 287 | self.Pi_dic[state] = 0.0 288 | self.B_dic[state] = {} 289 | 290 | Count_dic[state] = 0 291 | 292 | def makeLabel(text): 293 | out_text = [] 294 | if len(text) == 1: 295 | out_text.append('S') 296 | else: 297 | out_text += ['B'] + ['M'] * (len(text) - 2) + ['E'] 298 | 299 | return out_text 300 | 301 | init_parameters() 302 | line_num = -1 303 | # 观察者集合,主要是字以及标点等 304 | words = set() 305 | with open(path, encoding='utf8') as f: 306 | for line in f: 307 | line_num += 1 308 | print(line) 309 | 310 | line = line.strip() 311 | if not line: 312 | continue 313 | 314 | word_list = [i for i in line if i != ' '] 315 | words |= set(word_list) # 更新字的集合 316 | 317 | linelist = line.split() 318 | 319 | line_state = [] 320 | for w in linelist: 321 | line_state.extend(makeLabel(w)) 322 | 323 | assert len(word_list) == len(line_state) 324 | 325 | for k, v in enumerate(line_state): 326 | Count_dic[v] += 1 327 | if k == 0: 328 | self.Pi_dic[v] += 1 # 每个句子的第一个字的状态,用于计算初始状态概率 329 | else: 330 | self.A_dic[line_state[k - 1]][v] += 1 # 计算转移概率 331 | self.B_dic[line_state[k]][word_list[k]] = \ 332 | self.B_dic[line_state[k]].get(word_list[k], 0) + 1.0 # 计算发射概率 333 | 334 | self.Pi_dic = {k: v * 1.0 / line_num for k, v in self.Pi_dic.items()} 335 | self.A_dic = {k: {k1: v1 / Count_dic[k] for k1, v1 in v.items()} 336 | for k, v in self.A_dic.items()} 337 | # 加1平滑 338 | self.B_dic = {k: {k1: (v1 + 1) / Count_dic[k] for k1, v1 in v.items()} 339 | for k, v in self.B_dic.items()} 340 | # 序列化 341 | import pickle 342 | with open(self.model_file, 'wb') as f: 343 | pickle.dump(self.A_dic, f) 344 | pickle.dump(self.B_dic, f) 345 | pickle.dump(self.Pi_dic, f) 346 | 347 | return self 348 | 349 | def viterbi(self, text, states, start_p, trans_p, emit_p): 350 | V = [{}] 351 | path = {} 352 | for y in states: 353 | V[0][y] = start_p[y] * emit_p[y].get(text[0], 0) 354 | path[y] = [y] 355 | for t in range(1, len(text)): 356 | V.append({}) 357 | newpath = {} 358 | 359 | # 检验训练的发射概率矩阵中是否有该字 360 | neverSeen = text[t] not in emit_p['S'].keys() and \ 361 | text[t] not in emit_p['M'].keys() and \ 362 | text[t] not in emit_p['E'].keys() and \ 363 | text[t] not in emit_p['B'].keys() 364 | for y in states: 365 | emitP = emit_p[y].get(text[t], 0) if not neverSeen else 1.0 # 设置未知字单独成词 366 | (prob, state) = max( 367 | [(V[t - 1][y0] * trans_p[y0].get(y, 0) * 368 | emitP, y0) 369 | for y0 in states if V[t - 1][y0] > 0]) 370 | V[t][y] = prob 371 | newpath[y] = path[state] + [y] 372 | path = newpath 373 | 374 | if emit_p['M'].get(text[-1], 0) > emit_p['S'].get(text[-1], 0): 375 | (prob, state) = max([(V[len(text) - 1][y], y) for y in ('E', 'M')]) 376 | else: 377 | (prob, state) = max([(V[len(text) - 1][y], y) for y in states]) 378 | 379 | return (prob, path[state]) 380 | 381 | def cut(self, text): 382 | import os 383 | if not self.load_para: 384 | self.try_load_model(os.path.exists(self.model_file)) 385 | prob, pos_list = self.viterbi(text, self.state_list, self.Pi_dic, self.A_dic, self.B_dic) 386 | begin, next = 0, 0 387 | for i, char in enumerate(text): 388 | pos = pos_list[i] 389 | if pos == 'B': 390 | begin = i 391 | elif pos == 'E': 392 | yield text[begin: i + 1] 393 | next = i + 1 394 | elif pos == 'S': 395 | yield char 396 | next = i + 1 397 | if next < len(text): 398 | yield text[next:] 399 | 400 | if __name__ == '__main__': 401 | hmm = HMM() 402 | hmm.train('./data/trainCorpus.txt_utf8') 403 | print('训练完成') 404 | text = input('输入一个句子:') 405 | result = hmm.cut(text) 406 | print(str(list(result))) 407 | ``` 408 | 409 | - 其他统计分词算法 410 | 411 | - 条件随机场(CRF) 412 | - 神经网络分词算法(CNN、LSTM) 413 | 414 | --- 415 | 416 | # 3.5 中文分词工具——Jieba 417 | 418 | - 使用Jieba的优点 419 | 420 | - 社区活跃 421 | - 功能丰富 422 | - 使用简单 423 | - 提供多种编程语言实现 424 | 425 | - [官网地址](https://github.com/fxsjy/jieba) 426 | 427 | - 简介 428 | 429 | 结合基于规则和统计的两类方法,首先基于前缀词典(指词典中的词按照前缀包含的顺序排列)进行词图扫描,从而形成一种层级包含结构。这样可以快速构建包含全部可能分词结果的有向无环图,图中包含多条分词路径,有向指全部路径都始于第一个字、止于最后一个字,而无环则指节点间不构成闭环。基于标注语料,使用动态规划方法找出最大概率路径并将其作为最终分词结果。而对于OOV,则使用基于汉字成词的HMM模型,采用Viterbi算法进行推导。 430 | 431 | - 三种分词模式 432 | 433 | - 精确模式:试图将句子最精确的切分,适合文本分析; 434 | - 全模式:将句子中所有可以成词的词语都扫描出来,速度快,但存在歧义问题; 435 | - 搜索引擎模式:在精确模式的基础上,多长词再切分,提高召回率,适用于搜索引擎分词; 436 | 437 | ```python 438 | 439 | #!/usr/bin/env python 440 | # -*- coding: utf-8 -*- 441 | # @version : 1.0 442 | # @Time : 2019-8-26 21:33 443 | # @Author : cunyu 444 | # @Email : cunyu1024@foxmail.com 445 | # @Site : https://cunyu1943.github.io 446 | # @File : jieba_demo.py 447 | # @Software: PyCharm 448 | # @Desc : jieba简单使用 449 | 450 | # 三种模式对比 451 | 452 | import jieba 453 | sent = '中文分词是文本处理中不可获取的一步!' 454 | 455 | seg_list = jieba.cut(sent,cut_all=True) 456 | print('全模式: ', '/'.join(seg_list)) 457 | 458 | seg_list = jieba.cut(sent,cut_all=False) 459 | print('精确模式: ', '/'.join(seg_list)) 460 | 461 | seg_list = jieba.cut_for_search(sent) 462 | print('搜索引擎模式: ', '/'.join(seg_list)) 463 | ``` 464 | 465 | ![三种模式结果](https://i.loli.net/2019/08/26/kbvUfJIiZ2wcCdH.png) 466 | 467 | - 高频词提取 468 | 469 | 高频词指文档中出现频率较高且非无用的词语,在一定程度上代表了文档的焦点所在,主要有以下干扰: 470 | 471 | - 标点符号 472 | - 停用词 473 | 474 | ```python 475 | 476 | #!/usr/bin/env python 477 | # -*- coding: utf-8 -*- 478 | # @version : 1.0 479 | # @Time : 2019-8-27 9:16 480 | # @Author : cunyu 481 | # @Email : cunyu1024@foxmail.com 482 | # @Site : https://cunyu1943.github.io 483 | # @File : keyWords.py 484 | # @Software: PyCharm 485 | # @Desc : 关键词抽取 486 | 487 | import glob 488 | import random 489 | import jieba 490 | 491 | # 读取文件 492 | def get_content(path): 493 | with open(path, 'r', encoding='gbk', errors='ignore') as f: 494 | content = '' 495 | for l in f: 496 | l = l.strip() 497 | content += l 498 | return content 499 | 500 | # 获取高频词 501 | def get_TF(words, topK=10): 502 | tf_dic = {} 503 | for w in words: 504 | tf_dic[w] = tf_dic.get(w, 0) + 1 505 | return sorted(tf_dic.items(), key=lambda x: x[1], reverse=True)[:topK] 506 | 507 | # 加载停用词 508 | def stop_words(path): 509 | with open(path) as f: 510 | return [l.strip() for l in f] 511 | 512 | # 分词 513 | def main(path,stop_words_path): 514 | 515 | files = glob.glob(path) 516 | corpus = [get_content(x) for x in files[:5]] 517 | # 随机产生一个随机数(小于总的长度)个样本,然后对这几个样本进行提取高频词操作 518 | sample_inxs = random.randint(0, len(corpus)) 519 | for sample_inx in range(sample_inxs): 520 | split_words = [x for x in jieba.cut(corpus[sample_inx]) if x not in stop_words(stop_words_path)] 521 | print('样本之一:' + corpus[sample_inx]) 522 | print('样本分词效果:' + '/ '.join(split_words)) 523 | print('样本的topK(10)词:' + str(get_TF(split_words))) 524 | 525 | if __name__ == '__main__': 526 | path = './data/news/C000010/*.txt' 527 | stop_words_path='./data/stop_words.utf8' 528 | main(path, stop_words_path) 529 | ``` 530 | 531 | --------------------------------------------------------------------------------