1. 搭建NLTK环境
1.1 操作系统
本教程用的操作系统是Windows 10 x64(如果你使用的是32位系统,则应升级为64位的操作系统;如果你安装的是Windows 7或XP,则无需升级到Windows 10操作系统)。
1.2 Python开发环境
本教程使用的是当前最新版本的Python-3.7版本。
安装方法,我是用过两种。
第一种是标准方法,也就是到官网上下载最新版本。
第二种是使用 Anaconda跨平台安装包,可以到官网 https://www.continuum.io/downloads 上自行下载,部分教程可以参考本人博客相关内容。
编辑器用的是Pycharm。
1.3 安装常用Python应用程序
-
安装数学运算包。
pip install numpy
conda install scipy -
安装mysql数据库工具包 。
略 -
安装Tornado网络包 。
pip install Tornado
-
安装NLTK开发环境。
(1)安装NLTK语言开发系统的基本指令。pip install nltk
(2)下载常用语料库:NLTK,执行如下代码可下载相关的语料。
import nltk
nltk.download()出现如图所示界面:
注意,如果在Pycharm中运行代码。import nltk
可能会报一系列错误,主要表示无法获取模块。然而这个时候感觉一切都是正确的(python用的是Anaconda的虚拟环境,Anaconda环境变量配置完整,cmd中执行上述代码没有问题),却找不到正确方法。建议重启电脑,清理电脑垃圾(360),在cmd上运行一遍,在觉得比较通畅的时候,再在Pycharm上再试一遍。如果没有报错,那就说明成功了。如果按照上面安装nltk的参考链接,已经将nltk_data下载到了本地,结果是老是显示网络链接超时,只跳出来窗口,不显式各种库,只需点击refresh,慢慢地各种库就会显示出来。
这个在整合句法分析模块用的到,现在也不必太过着急,可以回头参考,免得事倍功半。
2. 整合中文分词模块
这里将几个开源的NLP系统整合到NLTK中。
本节主要介绍【中文分词】部分。汉语自然语言处理的第一部分是中文分词。 因为中文不像英文那样,实行分词连写,即词与词之间用空格分隔。在分析中文文本之前必须将一个汉字序列切分成一个一个单独的词。这个过程称为中文分词(Chinese Word Segmentation)。
按照使用的算法不同,介绍两大类中文分词模块
- 基于条件随机场(CRF)的中文分词算法的开源系统。
- 基于张华平NShort的中文分词算法的开源系统。
2.1 安装Ltp Python组件
国内使用CRF做中文分词的开源系统主要为哈工大的HIT LTP语言技术平台。
(1)pyltp安装。
pip install pyltp
然而失败(我python3.5,3.7都试过了失败),报错原因:
c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\cl.exe’ failed with exit status 2
解决办法:
果断放弃pip和conda方法,参考链接这位仁兄的解决办法。
步骤1:添加VC路径到用户环境变量中,注意是用户环境变量中,而不是系统环境变量中。
变量名:VCINSTALLDIR (变量值为vs安装路径下的VC,默认是这个)
变量值(我的):C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
步骤2:
win+R运行cmd,执行命令:
set CL=/FI”%VCINSTALLDIR%\INCLUDE\stdint.h” %CL%
步骤3:
先下载pyltp压缩文件。下载链接:https://github.com/hit-scir/pyltp ,下载完成后,解压到任意一个文件夹下,如pyltp-master。注意,解压pyltp后所得到的文件夹中可能已经有一个名为ltp的空文件夹:
步骤4:
然后下载ltb压缩文件。下载;链接:https://github.com/hit-scir/ltp ,下载完成后,解压文件夹到任意一个文件夹中,如,ltp-master。
步骤5:
将ltp-master该文件夹重命名为ltp复制并覆盖pyltp的ltp文件夹。
步骤6:
win+R打开CMD,cd到pyltp目录下,然后输入python setup.py install,如下所示(我用的是Anaconda,所以有第一句激活命令,如果不是Anaconda忽略第一句)。
(base) C:\Users\Administrator>activate Anaconda-Pycharm
(Anaconda-Pycharm) C:\Users\Administrator>d:
(Anaconda-Pycharm) D:>cd D:\Anaconda3\envs\Anaconda-Pycharm\pyltp-master
(Anaconda-Pycharm) D:\Anaconda3\envs\Anaconda-Pycharm\pyltp-master>python setup.py install
结果是!!!!(神啊,让我成功吧!):
报错:
ltp/src/utils/strutils.hpp(344): warning C4267: ‘initializing’: conversion from ‘size_t’ to ‘int’, possible loss of data
ltp/src/utils/sbcdbc.hpp(67): warning C4267: ‘initializing’: conversion from ‘size_t’ to ‘int’, possible loss of data
ltp/src/utils/sbcdbc.hpp(85): warning C4267: ‘initializing’: conversion from ‘size_t’ to ‘int’, possible loss of data
ltp/src/utils/smartmap.hpp(617): warning C4267: ‘initializing’: conversion from ‘size_t’ to ‘int32_t’, possible loss of data
patch\libs\python\src\converter\builtin_converters.cpp(51): error C2440: ‘return’: cannot convert from ‘const char *’ to ‘void *’
patch\libs\python\src\converter\builtin_converters.cpp(51): note: Conversion loses qualifiers
patch\libs\python\src\converter\builtin_converters.cpp(442): warning C4244: ‘initializing’: conversion from ‘Py_ssize_t’ to ‘int’, possible loss of data
error: command ‘C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\cl.exe’ failed with exit status 2
可以看的出来前面都是warning,可以忽略,但是这里有一个报错的信息:
patch\libs\python\src\converter\builtin_converters.cpp(51): error C2440: ‘return’: cannot convert from ‘const char *’ to ‘void *’
错误原因:类型转换出错。
解决办法:(51)行加(void*),暴力解决,强制类型转换。
#if PY_VERSION_HEX < 0x03000000
void* convert_to_cstring(PyObject* obj)
{
return PyString_Check(obj) ? PyString_AsString(obj) : 0;
}
#else
void* convert_to_cstring(PyObject* obj)
{
return PyUnicode_Check(obj) ? (void*) _PyUnicode_AsString(obj) : 0;
}
#endif
再来试一下:
结果是:成功!!!!
Installed d:\anaconda3\envs\anaconda-pycharm\lib\site-packages\pyltp-0.2.1-py3.7-win-amd64.egg
Processing dependencies for pyltp==0.2.1Finished processing dependencies for pyltp==0.2.1
没得塔西,没得塔西
(2)部署语言模型库。
从链接:https://pan.baidu.com/s/1DQObXdIkGyS_Ne_h7ixrZg 提取码:40zu下载Ltp的模型文件,好几种,我自己用v3.4.0,解压在自己的某一个盘符下:cws.model为中文分词模块所需的语言模型,为二进制文件。
fulluserdict.txt为用户可添加的外部词典文件,貌似一开始并不存在,可以用户在运行过程中慢慢添加,如下面的实例,结构如图所示。
2.2 使用Ltp3.4进行中文分词
(1)Ltp3.4 安装成功之后,新建一个Python文件:
# -*- coding: utf-8 -*-
from pyltp import Segmentor # 导入ltp库
segmentor = Segmentor() # 实例化分词模块
segmentor.load("D:/ltp_3.4/cws.model")# 加载分词库
words = segmentor.segment("在包含问题的所有解的解空间树种,按照深度优先搜索的策略,从根节点出发深度探索解空间树。")# ,调用分词函数,设置分词对象
print("|".join(words))# 打印分词结果
segmentor.release()
执行结果如下:
在|包含|问题|的|所有|解|的|解|空间|树种|,|按照|深度|优先|搜索|的|策略|,|从|根节点|出发|深度|探索|解|空间|树|。
(2)分词结果的处理。
观察上述分词结果,“解|空间”、“解|空间|树”、“深度|优先”都可以看作一个完成的专有名词:解空间、解空间树、深度优先,所以说,分词器划分的【粒度过细】。
为了获得更精确的结果,可以将错分的结果合并为【专有名词】。这就是分词结果的后处理过程,即【一般外部用户词典的构成原理】。
# -*- coding: utf-8 -*-
from pyltp import Segmentor # 导入ltp库
postdict={
"解|空间":"解空间","深度|优先":"深度优先"}# 分词后处理——矫正一些错误的结果
segmentor = Segmentor() # 实例化分词模块
segmentor.load("D:/ltp_3.4/cws.model")# 加载分词库
words = segmentor.segment("在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根节点出发深度探索解空间树。")# 设置分词对象
seg_sent = "|".join(words)# 分割后的分词结果
print("分割后的分词结果 :"+seg_sent)
for key in postdict:
seg_sent=seg_sent.replace(key,postdict[key])
print("分词后处理的分词结果 : "+seg_sent)# 打印分词后处理的分词结果
segmentor.release()
分词结果如下:
分割后的分词结果 :在|包含|问题|的|所有|解|的|解|空间|树|中|,|按照|深度|优先|搜索|的|策略|,|从|根节点|出发|深度|探索|解|空间|树|。
分词后处理的分词结果 : 在|包含|问题|的|所有|解|的|解空间|树|中|,|按照|深度优先|搜索|的|策略|,|从|根节点|出发|深度|探索|解空间|树|。
(3)现在加入用户词典,词典中登陆一些新词,如解空间。
javascript
2.3 使用结巴分词模块
张华平NShort的中文分词算法是目前最大规模中文分词的主流算法。在商用领域,大多数搜索引擎公司都使用该算法做欸主要的分词算法。具有算法原理简单、容易理解、便于训练、大规模分词的效率高、模型支持增量扩展、模型占用资源低等优势。
结巴分词的算法核心就是NShort中文分词算法。
(1)结巴分词库的安装。
pip install jieba
结巴分词下载地址:https://github.com/fxsjy/jieba 下载完解压到任一文件夹,如,D:\jieba-master,命令如下:
(base) C:\Users\Administrator>activate Anaconda-Pycharm
(Anaconda-Pycharm) C:\Users\Administrator>d:
(Anaconda-Pycharm) D:>cd D:\jieba-master
(Anaconda-Pycharm) D:\jieba-master>python setup.py install
(2)使用结巴分词
# -*- coding: utf-8 -*-
import jieba # 导入结巴分词库
# 结巴分词--全模式
sent = '在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根节点出发深度探索解空间树。'
wordlist = jieba.cut(sent, cut_all=True)
print('|'.join(wordlist))
# 结巴分词--精确切分
wordlist = jieba.cut(sent) # cut_all = False
print('|'.join(wordlist))
# 结巴分词--搜索引擎模式
wordlist = jieba.cut_for_search(sent)
print('|'.join(wordlist))
分词结果如下。
D:\Anaconda3\envs\Anaconda-Pycharm\python.exeD:/PycharmProjects/NLP/jieba_test.py
Building prefix dict from the default dictionary …
Dumping model to file cacheC:\Users\Administrator\AppData\Local\Temp\jieba.cache
在|包含|问题|的|所有|解|的|解空|空间|树|中|||按照|深度|优先|搜索|的|策略|||从|根|节点|点出|出发|深度|探索|索解|解空|空间|树||
在|包含|问题|的|所有|解|的|解|空间|树中|,|按照|深度|优先|搜索|的|策略|,|从根|节点|出发|深度|探索|解|空间|树|。
在|包含|问题|的|所有|解|的|解|空间|树中|,|按照|深度|优先|搜索|的|策略|,|从根|节点|出发|深度|探索|解|空间|树|。
Loading model cost 1.191 seconds.
Prefix dict has been built successfully.进程已结束,退出代码 0
结巴分词的基础词库较之Ltp分词要少一些,标准词典的词汇量约有35万个。上例的分词结果显示,一些专有名词的切分缺乏足够的精度,不仅出现粒度问题,还出现错分问题(如上例中的“树中”、“从根”)。由此可见分词器的精度不仅受到算法的影响,更受到语言模型库的规模影响。这一点对于NShort最短路径算法尤其明显。
(3)定义用户词典。
如,词典文件userdict.txt
解空间 5 n
解空间树 5 n
根节点 5 n
深度优先 5 n
词典格式为一个词占一行;每一行分为三部分:词与、词频和词性,用空格隔开,顺序不可颠倒。userdict.txt文件必须为UTF-8编码。
结巴分词中的词典词频设置,默认为5。这个数越大,说明该字符串的概率越高,受内置词典的干扰就越小;这个数越小,用户词典内的词收到内置词典的干扰越强,不能受到正确切分的概率就越大。用户根据实际情况来设置这个值。
(4)使用用户词典。
# -*- coding: utf-8 -*-
import jieba # 导入结巴分词库
jieba.load_userdict("userdict.txt") #加载外部 用户词典
sent = '在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根节点出发深度探索解空间树。'
# 结巴分词--精确切分
wordlist = jieba.cut(sent) # cut_all = False
print('|'.join(wordlist))
分词结果如下。
Building prefix dict from the default dictionary …
Loading model from cache C:\Users\Administrator\AppData\Local\Temp\jieba.cache
Loading model cost 1.104 seconds.
在|包含|问题|的|所有|解|的|解空间树|中|,|按照|深度优先|搜索|的|策略|,|从|根节点|出发|深度|探索|解空间树|。
Prefix dict has been built successfully.
3. 整合词性标注模块
【词性标注】(Part-of-Speech Tagging或POS Tagging),又称为词类标注,是指判断处在一个句子中没歌词所扮演的语法角色。例如,表示人、事物、地点或抽象概念的名称就是名词;表示动作或状态变换的词为动词;用来描写或修饰名词性成分或表示概念的性质、状态、特征或属性的词称为形容词,等等。
在汉语中,常用词的词性都不是固定的,也就是说,一个词可能具有多个词性。
本节主要介绍几个中文词性标注系统的应用。一般而言,中文的词性标注算法比较统一,大多数使用【HMM】(隐马尔科夫模型)或【最大熵算法】,如前文中的结巴分词的词性标注实现。为了获得更高的精度,也有使用【CRF算法】的,如Ltp3.4中的词性标注。虽然分词与词性标注是两个不同的模块,但是在一般的工程应用中,语料的【中文分词】和【词性标注】通常同时完成。
目前流行的中文词性标签有两大类:北大词性标注集和宾州词性标注集。两大标注方式各有千秋,为了更全面地反应中文标注的概况,我们使用Stanford大学的中文词性标注模块作为另一个中文词性标注系统。
3.1 Ltp 3.4 词性标注
# -*- coding: utf-8 -*-
from pyltp import Segmentor
from pyltp import Postagger
words = "在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根节点出发深度探索解空间树。"
segmentor = Segmentor() # 实例化分词模块
segmentor.load("D:/ltp_3.4/cws.model")# 加载分词库
words = segmentor.segment(words)# 调用分词函数
words = '|'.join(words)
sent = words.split('|')
postagger = Postagger() # 实例化词性标注类
postagger.