前文第一部分详细介绍了各种Python网络数据爬取方法,但所爬取的语料都是中文知识,在第二部分前面的章节也讲述了常用的数据分析模型及实例。这些实例都是针对数组或矩阵语料进行分析的,那么如何对中文文本语料进行数据分析呢?在本章作者将带领大家走进文本聚类分析领域,讲解文本预处理和文本聚类等实例内容。
数据预处理(DataPreprocessing)是指在进行数据分析之前,对数据进行的一些初步处理,包括缺失值填写、噪声处理、不一致数据修正、中文分词等,其目标是得到更标准、高质量的数据,纠正错误异常数据,从而提升分析的结果。
图1是数据预处理的基本步骤,包括中文分词、词性标注、数据清洗、特征提取(向量空间模型存储)、权重计算(TF-IDF)等。
1.中文分词技术及Jieba工具
在得到语料之后,首先需要做的就是对中文语料进行分词。由于中文词语之间是紧密联系的,一个汉语句子是由一串前后连续的汉字组成,词与词之间没有明显的分界标志,所以需要通过一定的分词技术把句子分割成空格连接的词序列。本章介绍了中文常用的分词技术,同时着重讲解了Python常用分词工具Jieba进行分词的实例。
2.数据清洗及停用词过滤
在使用Jieba中文分词技术得到分完词的语料后,可能会存在脏数据和停用词等现象。为了得到更好的数据分析结果,需要对这些数据集进行数据清洗和停用词过滤等操作,这里利用Jieba库进行清洗数据。
3.词性标注
4.特征提取
特征提取是指将原始特征转换为一组具有明显物理意义或者统计意义的核心特征,所提取的这组特征可以尽可能地表示这个原始语料,提取的特征通常会存储至向量空间模型中。向量空间模型是用向量来表征一个文本,它将中文文本转化为数值特征。本章介绍了特征提取、向量空间模型和余弦相似性的基本知识,同时结合实例进行深入讲解。
5.权重计算及TFIDF
在建立向量空间模型过程中,权重的表示尤为重要,常用方法包括布尔权重、词频权重、TF-IDF权重、熵权重方法等。本章讲述了常用的权重计算方法,并详细讲解了TF-IDF的计算方法和实例。
现在假设存在表1所示的数据集,并存储至本地test.txt文件中,整章内容都将围绕该数据集进行讲解,数据集共分为9行数据,包括3个主题,即:贵州旅游、大数据和爱情。接下来依次对数据预处理的各个步骤进行分析讲解。
中文分词(ChineseWordSegmentation)指将汉字序列切分成一个个单独的词或词串序列,它能够在没有词边界的中文字符串中建立分隔标志,通常采用空格分隔。中文分词是数据分析预处理、数据挖掘、文本挖掘、搜索引擎、知识图谱、自然语言处理等领域中非常基础的知识点,只有经过中文分词后的语料才能转换为数学向量的形式,继续进行后面的分析。同时,由于中文数据集涉及到语义、歧义等知识,划分难度较大,比英文复杂很多。下面举个简单示例,对句子“我是程序员”进行分词操作。
输入:我是程序员输出1:我\是\程\序\员输出2:我是\是程\程序\序员输出3:我\是\程序员这里分别采用了三种方法介绍中文分词。
中文分词方法有很多,常见的包括:
这里介绍比较经典的基于字符串匹配的分词方法。
正向最大匹配法的步骤如下,假设自动分词词典中的最长词条所含汉字的个数为n。
例如,现在存在一个句子“北京理工大学生前来应聘”,使用正向最大匹配方法进行中文分词的过程如下所示。
分词算法:正向最大匹配法输入字符:北京理工大学生前来应聘分词词典:北京、北京理工、理工、大学、大学生、生前、前来、应聘最大长度:6匹配过程:
随着中文数据分析越来越流行、应用越来越广,针对其语义特点也开发出了各种各样的中文分词工具,常见的分词工具包括:
同时针对Python语言的常见中文分词工具包括:盘古分词、Yaha分词、Jieba分词等,它们的用法都相差不大,由于结巴分词速度较快,可以导入词典如“颐和园”、“黄果树瀑布”等专有名词再进行中文分词等特点,本文主要介绍结巴(Jieba)分词工具讲解中文分词。
(1)安装过程
作者推荐大家使用PIP工具来安装Jieba中文分词包。安装语句如下:
pipinstalljieba调用命令“pipinstalljieba”安装jieba中文分词包如图所示。
同时,如果您使用AnacondaSpyder集成环境,则调用“AnacondaPrompt”命令行模式输入“pipinstalljieba”命令进行安装。如果您的Python开发环境已经安装了该扩展包,则会提示已经存在Jieba中文分词包,如图所示。
(2)基础用法
首先读者看一段简单的结巴分词代码。
Python提供的结巴(Jieba)中文分词包主要利用基于Trie树结构实现高效的词图扫描(构建有向无环图DAG)、动态规划查找最大概率路径(找出基于词频的最大切分组合)、基于汉字成词能力的HMM模型等算法,这里不进行详细叙述,本书更侧重于应用案例。同时结巴分词支持繁体分词和自定义字典方法。
(3)中文分词实例
下面对表1中的语料进行中文分词。代码为依次读取文件中的内容,并调用结巴分词包进行中文分词,然后存储至本地文件中。
#coding=utf-8#By:EastmountCSDNimportosimportcodecsimportjiebaimportjieba.analysesource=open("test.txt",'r')line=source.readline().rstrip('')content=[]whileline!="":seglist=jieba.cut(line,cut_all=False)#精确模式output=''.join(list(seglist))#空格拼接print(output)content.append(output)line=source.readline().rstrip('')else:source.close()输出如图所示,可以看到分词后的语料。
在分析语料的过程中,通常会存在一些脏数据或噪声词组干扰我们的实验结果,这就需要对分词后的语料进行数据清洗(DataCleaning)。比如前面使用Jieba工具进行中文分词,它可能存在一些脏数据或停用词,如“我们”、“的”、“吗”等。这些词降低了数据质量,为了得到更好的分析结果,需要对数据集进行数据清洗或停用词过滤等操作。本节主要介绍数据清洗概念、中文数据清洗技术及停用词过滤,并利用Jieba分词工具进行停用词和标点符号的清洗。
脏数据通常是指数据质量不高、不一致或不准确的数据,以及人为造成的错误数据等。作者将常见的脏数据分为四类:
数据清洗主要解决脏数据,从而提升数据质量,它主要应用于数据仓库、数据挖掘、数据质量管理等领域。读者可以简单将数据清洗定位为:只要是有助于解决数据质量问题的处理过程就被认为是数据清洗,不同领域的数据清洗定义有所不同。总之,数据清洗的目的是保证数据质量,提供准确数据,其任务是通过过滤或者修改那些不符合要求的数据,从而更好地为后面的数据分析作铺垫。
为了解决上述问题,将数据清洗方法划分为:
前面已将Python爬取的中文文本语料进行了分词处理,接下来需要对其进行数据清洗操作,通常包括停用词过滤和特殊标点符号去除等,而对于空值数据、重复数据,作者更建议大家在数据爬取过程中就进行简单的判断或补充缺失值。下面对表1所提供的中文语料(包括贵州、大数据和爱情三个主题)进行数据清洗实例操作。
(1)停用词过滤
上图是使用结巴工具中文分词后的结果,但它存在一些出现频率高却不影响文本主题的停用词,比如“数据分析是数学与计算机科学相结合的产物”句子中的“是”、“与”、“的”等词,这些词在预处理时是需要进行过滤的。
这里作者定义一个符合该数据集的常用停用词表的数组,然后将分词后的序列,每一个字或词组与停用词表进行比对,如果重复则删除该词语,最后保留的文本能尽可能地反应每行语料的主题。代码如下:
核心代码是for循环判断分词后的语料是否在停用词表中,如果不在则添加到新的数组final中,最后保留的就是过滤后文本,如图所示。
(2)去除标点符号
在做文本分析时,标点符号通常也会被算成一个特征,从而影响分析的结果,所以我们需要把标点符号也进行过滤。其过滤方法和前面过滤停用词的方法一致,建立一个标点符号的数组或放到停用词stopwords中,停用词数组如下:
stopwords={}.fromkeys(['的','或','等','是','有','之','与','和','也','被','吗','于','中','最','“','”','。',',','?','、',';'])同时将文本内容存储至本地result.txt文件中,完整代码如下:
#coding=utf-8#By:EastmountCSDNimportosimportcodecsimportjiebaimportjieba.analyse#停用词表stopwords={}.fromkeys(['的','或','等','是','有','之','与','和','也','被','吗','于','中','最','“','”','。',',','?','、',';'])source=open("test.txt",'r')result=codecs.open("result.txt",'w','utf-8')line=source.readline().rstrip('')content=[]#完整文本whileline!="":seglist=jieba.cut(line,cut_all=False)#精确模式final=[]#存储去除停用词内容forseginseglist:ifsegnotinstopwords:final.append(seg)output=''.join(list(final))#空格拼接print(output)content.append(output)result.write(output+'\r')line=source.readline().rstrip('')else:source.close()result.close()输出结果如图7所示,得到的语料非常精炼,尽可能的反应了文本主题,其中1-3行为贵州旅游主题、4-6为大数据主题、7-9位爱情主题。
本小节主要介绍特征提取、向量空间模型和余弦相似性的基础知识,并用表21.1所提供的语料进行基于向量空间模型的余弦相似度计算。
(1)特征提取
特征提取是将原始特征转换为一组具有明显物理意义或者统计意义的核心特征,所提取的这组特征可以尽可能地表示这个原始语料。特征提取分为线性特征提取和非线性特征提取,其中线性特征提取常见的方法包括:
非线性特征提取常见方法包括KernelPCA、KernelFDA等。
(2)特征选择
特征选择是从特征集合中挑选一组最具统计意义的特征,从而实现降维,通常包括产生过程、评价函数、停止准则、验证过程四个部分。传统方法包括信息增益(InformationGain,简称IG)法、随机产生序列选择算法、遗传算法(GeneticAlgorithms,简称GA)等。
下图是图像处理应用中提取Lena图的边缘线条特征的实例,可以利用一定量的特征尽可能的描述整个人的轮廓,它和数据分析中的应用也是相同的原理。
向量空间模型(VectorSpaceModel,简称VSM)是通过向量的形式来表征一个文档,它能够将中文文本转化为数值特征,从而进行数据分析。作为目前最为成熟和应用最广的文本表示模型之一,向量空间模型已经广泛应用于数据分析、自然语言处理、中文信息检索、数据挖掘、文本聚类等领域,并取得了一定成果。
采用向量空间模型来表示一篇文本语料,它将一个文档(Document)或一篇网页语料(WebDataset)转换为一系列的关键词(Key)或特征项(Term)的向量。
特征项(Trem)
特征项是指文档所表达的内容由它所含的基本语言单位(字、词、词组或短语)组成,在文本表示模型中,基本语言单位即称为文本的特征项。例如文本Doc中包含n个特征项,表示为:
特征权重(TremWeight)
特征权重是指为文档中的某个特征项ti(1≤i≤n)赋予权重wi,以表示该特征项对于文档内容的重要程度,权重越高的特征项越能反应其在文档中的重要性。文本Doc中存在n个特征项,即:{t1,t2,t3,…,tn-1,tn},它是一个n维坐标,接着需要计算出各特征项ti在文本中的权重wi,为对应特征的坐标值。按特征权重文本表示如下,其中,WDoc称为文本Doc的特征向量。
文档表示
得到了特征项和特征权重后,需要表示一篇文档,则利用下面这个公式。其中,文档Doc共包含n个特征词和n个权重。ti是一系列相互之间不同的特征词,i=1,2,…,n。wi(d)是特征词ti在文档d中的权重,它通常可以被表达为ti在d中呈现的频率。
特征项权重W有很多种不同的计算方法,最简单的方法是以特征项在文本中的出现次数作为该特征项的权重,第五部分将详细叙述。
从上图可以看到,将文档存储为词频向量的过程,转换为{1,0,1,0,…,1,1,0}形式。特征项的选取和特征项权重的计算是向量空间模型的两个核心问题,为了使特征向量更能体现文本内容的含义,要为文本选择合理的特征项,并且在给特征项赋权重时遵循对文本内容特征影响越大的特征项的权值越大的原则。
下图是向量空间模型图,它展示了文档Term1、Term2、…、TermN之间的余弦相似度计算方法,如果两篇文档越相似,则其夹角θ越小,Cos值越接近于1,当两篇文档完全相似时,此时的夹角为0°,Cos值为1。这也展示了余弦相似性的原理知识。
下面我们借用两个句子来计算其与“北京理工大学生前来应聘”的余弦相似程度。假设存在三个句子,需要看哪一个句子和“北京理工大学生前来应聘”相似程度更高,则认为主题更为类似。那么,如何计算句子A和句子B的相似性呢?
句子1:北京理工大学生前来应聘句子2:清华大学大学生也前来应聘句子3:我喜欢写代码下面采用向量空间模型、词频及余弦相似性计算句子2和句子3分别与句子1的相似性。
第一步:中文分词。
句子1:北京理工/大学生/前来/应聘句子2:清华大学/大学生/也/前来/应聘句子3:我/喜欢/写/代码第二步:列出所有词语,按照词出现的先后顺序。
北京理工/大学生/前来/应聘/清华大学/也/我/喜欢/写/代码第三步:计算词频。如表所示。
第四步:写出词频向量。
句子1:[1,1,1,1,0,0,0,0,0,0]句子2:[0,1,1,1,1,1,0,0,0,0]句子3:[0,0,0,0,0,0,1,1,1,1]第五步:计算余弦相似度。
其结果显示句子1和句子2的相似度为0.67,存在一定的相似主题;而句子1和句子3的相似度为0,完全不相似。
总之,余弦相似度是一种非常有用的算法,只要是计算两个向量的相似程度,都可用它。当余弦值越接近1时,表明两个向量的夹角越接近0度,两个向量越相似。但余弦相似性作为最简单的相似度计算方法,也存在一些缺点,如计算量太大、词之间的关联性没考虑等。
前面讲述的词频权重计算的方法过于简单,下面就给大家介绍下其他权重计算方法。
权重计算是指通过特征权重来衡量特征项在文档表示中的重要程度,给特征词赋予一定的权重来衡量统计文本特征词。常用的权重计算方法包括:布尔权重、绝对词频、倒文档词频、TF-IDF、TFC、熵权重等。
(1)布尔权重
布尔权重是比较简单的权重计算方法,设定的权重要么是1,要么是0。如果在文本中出现了该特征词,则文本向量对应该特征词的分量赋值为1;如果该特征词没有在文本中出现,则分量为0。公式如下所示,其中wij表示特征词ti在文本Dj中的权重。
假设特征向量为:
现在需要计算句子“北京理工大学生前来应聘”的权重,则特征词在特征向量中存在的,对应分量为1,不存在的对应分量为0,最终特征向量结果为:
但是实际应用中,布尔权重0-1值是无法体现特征词在文本中的重要程度,那就衍生出了词频这种方法。
(2)绝对词频
词频方法又称为绝对词频(TermFrequency,简称TF),它首先计算特征词在文档中出现的频率,再来表征文本。通常使用tfij表示,即特征词ti在训练文本Dj中出现的频率。
假设句子为“北京理工大学的大学生和清华大学的大学生前来应聘”,而对应的特征词为:{北京理工,大学生,前来,应聘,清华大学,也,我,喜欢,写,代码,的,和},对应词频向量为:
前面所采用的向量空间模型计算文本余弦相似性的例子也使用的是词频,这是权重计算方法中最简单、有效的方法之一。
(3)倒文档频率
由于词频方法无法体现低频特征项的区分能力,往往存在某些特征项频率很高,却在文本中起到很低影响程度的现象,如“我们”、“但是”、“的”等词语;同时,有的特征项虽然出现的频率很低,但表达着整个文本的核心思想,起着至关重要的作用。
其中,参数|D|表示语料的文本总数,表示文本所包含特征词ti的数量。
在倒文档频率方法中,权重是随着特征词的文档数量的变化呈反向变化。如某些常用词“我们”、“但是”、“的”等,在所有文档中出现频率很高,但它的IDF值却非常低。甚至如果它每篇文档都出现,则log1的计算结果为0,从而降低了这些常用词的作用;相反,如果某篇介绍“Python”的词,仅仅在该篇文档中出现,它的作用就非常高。
同样还有很多权重计算方法,包括TF-IDF、熵权重、TF-IWF、基于错误驱动的特征权重算法等,读者可以自行研究,这里仅仅简单引入了最基础的几种方法。
TF-IDF(TermFrequency-InversDocumentFrequency)是近年来用于数据分析和信息处理经典的权重计算技术。该技术根据特征词在文本中出现的次数和在整个语料中出现的文档频率来计算该特征词在整个语料中的重要程度,其优点是能过滤掉一些常见却无关紧要的词语,尽可能多的保留影响程度高的特征词。
式中tfidfi,j表示词频tfi,j和倒文本词频idfi的乘积,TF-IDF中权重与特征项在文档中出现的频率成正比,与在整个语料中出现该特征项的文档数成反比。tfidfi,j值越大则该特征词对这个文本的重要程度越高。
TF词频的计算公式如下:
其中,ni,j为特征词ti在训练文本Dj中出现的次数,是文本Dj中所有特征词的个数,计算的结果即为某个特征词的词频。
TF-IDF公式推导如下所示:
Scikit-Learn是基于Python的机器学习模块,基本功能主要分为六个部分:分类、回归、聚类、数据降维、模型选择和数据预处理,具体可以参考官方网站上的文档。本书前面详细介绍了Scikit-Learn的安装及使用方法。这里主要使用Scikit-Learn中的两个类CountVectorizer和TfidfTransformer,用来计算词频和TF-IDF值。
计算result.txt文本的词频代码如下,下表是表1数据集被中文分词、数据清洗后的结果,如下所示。
#coding:utf-8#By:EastmountCSDNfromsklearn.feature_extraction.textimportCountVectorizer#存储读取语料一行预料为一个文档corpus=[]forlineinopen('result.txt','r',encoding="utf-8").readlines():corpus.append(line.strip())#将文本中的词语转换为词频矩阵vectorizer=CountVectorizer()#计算个词语出现的次数X=vectorizer.fit_transform(corpus)#获取词袋中所有文本关键词word=vectorizer.get_feature_names()forninrange(len(word)):print(word[n],end="")print('')#查看词频结果print(X.toarray())输出如下图所示。
#coding:utf-8#By:EastmountCSDNfromsklearn.feature_extraction.textimportCountVectorizerfromsklearn.feature_extraction.textimportTfidfTransformer#存储读取语料corpus=[]forlineinopen('result.txt','r',encoding="utf-8").readlines():corpus.append(line.strip())vectorizer=CountVectorizer()#将文本中的词语转换为词频矩阵X=vectorizer.fit_transform(corpus)#计算个词语出现的次数word=vectorizer.get_feature_names()#获取词袋中所有文本关键词forninrange(len(word)):print(word[n],end="")print('')print(X.toarray())#查看词频结果#计算TF-IDF值transformer=TfidfTransformer()print(transformer)tfidf=transformer.fit_transform(X)#将词频矩阵X统计成TF-IDF值#查看数据结构print(tfidf.toarray())#tfidf[i][j]表示i类文本中的tf-idf权重运行部分结果如下图所示。
TF-IDF值采用矩阵数组的形式存储,每一行数据代表一个文本语料,每一行的每一列都代表其中一个特征对应的权重,得到TF-IDF后就可以运用各种数据分析算法进行分析,比如聚类分析、LDA主题分布、舆情分析等等。
获取文本TF-IDF值之后,本小节简单讲解使用TF-IDF值进行文本聚类的过程,主要包括如下五个步骤:
代码如下。
图中共绘制了6个点,将数据聚集为三类,对应不同的颜色。其中对应的类标为:
它将第1、3行语料聚集在一起,类标为2;第2、4、5、6、9行聚集为一组,类标为0;第7、8行语料聚集为最后一组,类标为1。而真实数据集中,第1、2、3行表示贵州主题,第4、5、6行表示数据分析主题,第7、8、9行表示爱情主题,所以数据分析预测结果会存在一定误差,我们需要将误差尽可能的降低,类似于深度学习,也是在不断学习中进步。
您可能会疑惑为什么9行数据,却只绘制了6个点呢?下面是9行数据进行降维处理生成的X和Y坐标,可以看到部分数据是一样的,这是因为这9行语料所包含的词较少,出现的频率基本都是1次,在生成词频矩阵和TF-IDF后再经降维处理可能出现相同的现象,而真实分析中语料所包含词语较多,聚类分析更多的散点更能直观地反应分析的结果。
[[-0.198519360.594503][-0.075372610.03666604][-0.198519360.594503][-0.2836149-0.40631642][-0.27797826-0.39614944][-0.25516435-0.35198914][0.68227073-0.05394154][0.68227073-0.05394154][-0.075372610.03666604]]研究生期间,作者在研究知识图谱、实体对齐知识时,曾采用过KMeans聚类算法对所爬取的四个主题百科数据集进行文本聚类分析,其聚类结果如图所示。
图中红色表示旅游景点主题文本、绿色表示保护动物主题文本、蓝色表示人物明星主题文本、黑色表示国家地理主题文本。从图中可以发现四类主题分别聚集成四个类簇。这是文本分析的一个简单示例,希望读者能根据本章的知识点,分析自己所研究的文本知识。
前面讲述的数据分析内容几乎都是基于数字、矩阵的,而也有一部分数据分析会涉及文本处理分析,尤其是中文文本数据,它们究竟怎么处理呢?当我们通过网络爬虫得到中文语料之后,我们究竟能不能进行数据分析呢?答案肯定是能的。
最后希望读者能复现每一行代码,只有实践才能进步。同时更多聚类算法和原理知识,希望读者下来自行深入学习研究,也推荐大家结合Sklearn官网和开源网站学习更多的机器学习知识。