前面章节初步学习数据的采集和一些快速的数据分析方法,如果需要更加深入去做数据分析,那么会使用到更加丰富的知识。自然语言处理(NLP)的其中一个方向就是文本处理。后面两章节将讲解基础的文本分类的知识点,学习完成入门知识点后将在实践中开始数据分析之旅。
为了实现数值格式的特征输入,我们需要清洗、规范化和预处理文本数据。通常情况下,在进行文本分析之前拿到的文本数据都是杂乱无章,文本语料库和原始文本数据也并不是规范化的。所以文本的预处理是需要使用各种方法和技术,将原始的文本转成定义好的语言成本序列。
举例来讲,我们分析一封邮件是不是垃圾邮件,那就是通常所说的对邮件分类,那么我们需要通过对正常邮件和垃圾邮件的文本进行分析,分别把目前已有的垃圾邮件的样本进行清洗过滤,提取出垃圾邮件的特征,比如经过统计分词后得到了100个垃圾邮件关键词,如果某一个邮件中的词语在这100个词中出现了5个,那么可以预测这可能也是一封垃圾邮件。当然这个阈值是多少是需要模型来计算得出,这里仅仅举一个例子说明。
文本切分
1.句子切分
我们知道一篇文章是由段落组成,一个段落中有多个句子。那把文本语料库分解成句子的过程就是句子切分。这些句子是组成语料库的第一步。
基本的句子切分方法是在通过句子之间的分隔符号作为切分依据,比如句号(。/.)、逗号(,/,)、分号(;/;)、换行符(n)或者空格等等。根据这些符号来将每一个段落切分成每个句子。
在文本分析上,中文和英文还是有很大的不同,目前使用比较多的NLTK(Natural Language Toolkit,自然语言工具包)中提供了各种句子切分的方法。
在使用NLTK工具之前还是需要先安装它:
代码语言:javascript复制pip install nltk
安装完成后,直接调用sent_tokenize()函数来进行句子切分。
#导入nltk工具包
代码语言:javascript复制from nltk.tokenize import sent_tokenize
text = "Many people like the party of the Spring Festival. Some people suggest to cancel the party. I think it is necessary to have a party like this."
#使用sent_tokenize()切分句子
print(sent_tokenize(text))
现在这样运行一下,并不能得到想要的结果,会报错误:
LookupError:
**********************************************************************
Resource punkt not found.
Please use the NLTK Downloader to obtain the resource:
>>> import nltk
>>> nltk.download('punkt')
For more information see: https://www.nltk.org/data.html
Attempted to load tokenizers/punkt/english.pickle
Searched in:
……
- 'C:\nltk_data'
- 'D:\nltk_data'
- 'E:\nltk_data'
- ''
**********************************************************************
这个错误的意思是punkt没有下载,另外还给直接提示了下载方法。
>>> import nltk
>>> nltk.download('punkt')
按照提示使用download方法下载punkt:
[nltk_data] Downloading package punkt to D:nltk_data...
[nltk_data] Unzipping tokenizerspunkt.zip.
下载完成后打开目录:D:nltk_datatokenizerspunkt会看到下载下来的Punkt语料库文件,包含了一共18种语言。这是我们在重新运行上面的句子切分代码。
结果如下:
['Many people like the party of the Spring Festival.', 'Some people suggest to cancel
the party.', 'I think it is necessary to have a party like this.']
原来的三句话按照“.”切分成三句话,存在一个list中。我们可以发现Punkt预料库中虽然有18种语言,但是并没有中文的,如果切分中文的段落其实效果并不理想。不过既然我们知道了大体的句子切分的原理,我们可以根据中文的标点符号自己动手写一个。
代码语言:javascript复制#导入正则模块,使用re切分
import re
text = '很多人喜欢春节联欢晚会。有些人建议取消春晚?我认为有必要举行一次这样的晚会!'
result = re.split(r'(.|!|?|。|!|?)', text)
print(result)
#代码运行结果:
['很多人喜欢春节联欢晚会', '。', '有些人建议取消春晚', '?', '我认为有必要举行一次这样的晚会', '!', '']
得到结果虽然是根据中文的标签符号进行一一切分,不过其中的一些内容并不是我们最初想要的结果,还需要对这个符号进行去除。
但是在Python强大的三方库中,很多工作还是不需要手动去做。我们可以借助的处理中文标点符号的第三库:zhon
安装也很简单,使用pip安装:
代码语言:javascript复制pip install zhon
使用方法也很简单,直接在re模块中引用zhon中常量。
代码语言:javascript复制import re
from zhon import hanzi
text = '很多人喜欢春节联欢晚会。有些人建议取消春晚?我认为有必要举行一次这样的晚会!'
result = re.findall(hanzi.sentence, text)
print(result)
#代码运行结果:
['很多人喜欢春节联欢晚会。', '有些人建议取消春晚?', '我认为有必要举行一次这样的晚会!']
Zhon不仅仅支持中文标点符号,也支持汉语拼音,对于中文的支持还算是丰富。
2.词语切分
在前面的6.4.3小节为了制作词云时有接触到分词,其实就是词语切分。词语切分是将句子分解或者切割成词语的过程。词语切分在很多过程中是比较重要的,特别是在文本清洗和规范化处理上,词语切分的质量非常影响后面的结果。
在NLTK包中也有对词语切分的方法,使用的是word_tokenize(),使用方法跟砂上一小节中的句子切分方法sent_tokenize()相同。
代码语言:javascript复制from nltk.tokenize import word_tokenize
text = "Many people like the party of the Spring Festival. Some people suggest to cancel the party. I think it is necessary to have a party like this."
#词语(单词)切分
print(word_tokenize(text))
#代码运行结果:
['Many', 'people', 'like', 'the', 'party', 'of', 'the', 'Spring', 'Festival', '.', 'Some', 'people', 'suggest', 'to', 'cancel', 'the', 'party', '.', 'I', 'think', 'it', 'is', 'necessary', 'to', 'have', 'a', 'party', 'like', 'this', '.']
英文词语切分是非常容易做的, 因为有天然的优势,每个单词之间都是由空格。因为中文汉字是标意的语言,所以中文分词(Chinese Word Segmentation, CWS)有很大的难点是在于断句上,主要的难点在于以下几个:
- 交集型切分歧义,汉语词如AJB 类型,满足AJ 和JB 分别成词。比如,“天和服装厂”,“天和”是一个公司名字,而“和服”也是一种服饰名字。在当前语境中,词语切分是“天和”“服装厂”。
- 组合型切分歧义,汉语词如AB,满足A、B、AB 分别成词。比如,“小明有画画的才能”,这里的“才能”可以是作为一个名字表示技能。另一种“我什么时候才能达到年薪百万”,这是“才”和“能”是需要分开切词。
- 混合型切分歧义,汉语词包含如上两种共存情况。如“他说这桶水也太重了”,其中“太重了”是交集型字段,“太重”是组合型字段。
目前比较流行的几种中文分词技术有基于字符串匹配的分词方法、基于理解的分词方法和基于统计的分词方法。
基于字符串匹配的分词方法是一种基于词典的中文分词,核心是首先创建一个词典表,当对一个句子进行分词是,句子拆分成多个部分,每一个部分与字典一一查找,如果词语在此字典中,则分词成功,否则继续拆分继续直到匹配成功。这种方法的核心就是字典。优点是速度比较快,实现简单,比较依赖字典的丰富程度。
基于理解的分词方法是通过让计算机模拟人对句子的理解,达到识别词的效果。基本思想是在分词的同时进行句法、语义分析,利用上下文进行断句,使用语义信息处理歧义。这种分词需要大量的语言知识和信息,由于中文知识很比较复杂,这种分词方式的难度较高。
基于统计的分词方法是依照分词概率最大化的方法来处理,也就是基于语料库,统计相邻的字组成的词语的出现的概率,相邻的词出现的次数多,那么出现的概率大,按照概率值进行分词,这样分词方式也是需要一个完成的语料库。
虽然中文分词比起英文分词有天然的难点,不过目前也有很多中文的分词库,除了前面章节中使用的Jieba中文分词以外,还有不错的一些中文分词库。
SnowNLP
SnowNLP是一个Python写的类库,可以方便的处理中文文本内容,是受到了TextBlob的启发而写的,目前大部分的自然语言处理库基本是针对于英文,SnowNLP是为了方便处理中文的库而开发,与TextBlob不同的是,并没有用NLTK,所有的算法都是自行实现的,并且自带了一些训练好的字典。SnowNLP开源地址:https://github.com/isnowfy/snownlp
使用SnowNLP 同样是先安装:
代码语言:javascript复制pip install snownlp
SnowNLP的功能也比较丰富,除了中文分词外,还可以支持词性标注、转换成拼音、提取文本关键词、提取文本摘要等等功能。
代码语言:javascript复制from snownlp import SnowNLP
text = '很多人喜欢春节联欢晚会。有些人建议取消春晚。我认为有必要举行一次这样的晚会!'
s = SnowNLP(text)
print(s.words)
#代码运行结果:
['很多', '人', '喜欢', '春节', '联欢', '晚会', '。', '有些', '人', '建议', '取消', '春', '晚', '。', '我', '认为', '有', '必要', '举行', '一', '次', '这样', '的', '晚会', '!']
在结果中看SnowNLP分词效果并不是特别理想,在当前语境中“春晚”、“一次”等不应该是别拆分,也就是说分词的效果跟使用的工具有很大的关系。
Pkuseg
Pkuseg是一个多领域中文分词工具包,主要的亮点是多领域分词。不同于以往的通用中文分词工具,此工具包同时致力于为不同领域的数据提供个性化的预训练模型。根据待分词文本的领域特点,用户可以自由地选择不同的模型。Pkuseg目前支持了新闻领域,网络领域,医药领域,旅游领域,以及混合领域的分词预训练模型。
使用前先安装:
代码语言:javascript复制pip install Pkuseg
这两个包都比较大,安装起来比较慢,等待时间比较长。
代码语言:javascript复制import pkuseg
text = '很多人喜欢春节联欢晚会。有些人建议取消春晚。我认为有必要举行一次这样的晚会!'
# 以默认配置加载模型
seg = pkuseg.pkuseg()
# 进行分词
text = seg.cut(text)
print(text)
#代码运行结果:
['很多', '人', '喜欢', '春节', '联欢', '晚会', '。', '有些', '人', '建议', '取消', '春晚', '。', '我', '认为', '有', '必要', '举行', '一', '次', '这样', '的', '晚会', '!']
在pkuseg中“春晚”是作为了一个词语进行了切分,但是像“一次”这样的还是没有做到结合语境来切分。不过pkuseg的优势在于细分领域的分词,目前支持的有四个领域,我们找一个旅游领域的句子来看下。
代码语言:javascript复制import pkuseg
text = '圆明园路,碎砖铺设,由北京东路蜿蜒至南苏州路,第一次遇见便惊为天人,宁静、典雅的气质令人着迷,这条路上的每一栋历史建筑都让人忍不住按下快门。'
# 自动下载所对应的细领域模型,当前使用旅游领域模型
代码语言:javascript复制seg = pkuseg.pkuseg(model_name='tourism')
text = seg.cut(text) # 进行分词
print(text)
#代码运行结果:
['圆明园路', ',', '碎砖', '铺设', ',', '由', '北京东路', '蜿蜒', '至', '南苏州路', ',', '第一', '次', '遇见', '便', '惊为', '天人', ',', '宁静', '、', '典雅', '的', '气质', '令', '人', '着迷', ',', '这', '条', '路上', '的', '每', '一', '栋', '历史', '建筑', '都', '让', '人', '忍', '不住', '按', '下', '快门', '。']
在此模式下分词,效果不错,句子中“圆明园路”、“北京东路”、“南苏州路”都放在了一个词语中作为道路名称,而没有分开。
每一个分词工具包并不能做到百分百的完美分词,很多模型的准确率已经到95%以上。
文本规范化
文本规范化是指对文本进行转换、清洗以及将文本数据标准化形成可供NLP、分析系统和应用程序的使用的格式的过程。通常情况下,上一个小节的文本切分也是文本规范化的一部分。除了上述操作之外,还会进行一些文本清洗、词语矫正、停用词删除等等,对于英文来说,还会有大小写转换、缩略词还原等等操作。
1.文本清洗
文本清洗的操作是根据使用或者待分析的文本数据的质量来判断是否需要进行。如果原始文本中包含大量无关和不必要的标识和字符,那么在进行其他操作之前需要先删除它们。比如,很多时候在网络爬虫获取的数据中会夹杂HTML标签,这样标签对数据分析来说并没有什么实际意义。
清理的方式有很多,通常情况下可以使用BeautifulSoup库或者xml库来解析Html或者xml数据,也可以自定义逻辑,使用正则表达式中提取出有用的信息。
2.删除停用词
停用词在制作词云的时候有提到过,它是指那些没有或者只有极小意义的词语。通常在文本规范化过程中将他们文本中删除,以保留具有最大意义和语境的词语。像“了”,“的”,“嗯”,“是的”等等词语就是停用词。前面有提到目前比较常用的四个停用词列表,目前还没有普遍或已穷尽的停用词列表。每个领域或者每个方向都由其特定的停用词,所以这些额外需要进行维护。
在NLTK中也自带一个停用词列表,不过这都是面向英文的,用我们之前例子演示一下。
代码语言:javascript复制from nltk import word_tokenize
from nltk.corpus import stopwords
text = "Many people like the party of the Spring Festival. Some people suggest to cancel the party. I think it is necessary to have a party like this."
#加载英文停用词列表
stopwordsList = stopwords.words('english')
#删除停用词后的list
filterList = [word for word in word_tokenize(text) if word not in stopwordsList]
print(filterList)
#代码运行结果:
['Many', 'people', 'like', 'party', 'Spring', 'Festival', '.', 'Some', 'people', 'suggest', 'cancel', 'party', '.', 'I', 'think', 'necessary', 'party', 'like', '.']
在text文本中像“of”“the”“to”等等没有实际意义的词语是英文中的停用词,使用NLTK的停用词删除。使用这里的stopwords跟punkt一样,需要先下载。
>>> import nltk
>>> nltk.download('stopwords')
本节内容比较简短,主要工作是为了后面的文本分类、分析提供好的输入。在文本规范化方面上,中文和英文有很大差异,在英文文本中,规范化操作可能还需要一些缩写词扩展、大小写转换、拼写错误的单词校正等等方面的规范化处理。
在中文中,可能并不要这么多的内容,同样中文的难点是在分词上。目前在Python的第三方库中,像jieba等都是不错的库供我们使用,大大提高了我们的做数据分析的效率。下一章我们将学习初步的文本分类的方法和算法,为我们后面的综合项目实战打好基础。