python结巴分词去掉虚词_如何用Python提取中文关键词?

虽然这个功能实现起来并不复杂,但是其中也有些坑,需要避免踩进去的。

通过本文,我一步步为你演示如何用Python实现中文关键词提取这一功能。

环境 Python

第一步是安装Python运行环境。我们使用集成环境Anaconda。

请到这个网址 下载最新版的Anaconda。下拉页面,找到下载位置。根据你目前使用的系统,网站会自动推荐给你适合的版本下载。我使用的是macOS,下载文件格式为pkg。

下载页面区左侧是Python 3.6版,右侧是2.7版。请选择2.7版本。

双击下载后的pkg文件,根据中文提示一步步安装即可。

样例

我专门为你准备了一个github项目,存放本文的配套源代码和数据。请从这个地址下载压缩包文件,然后解压。

解压后的目录名称为demo-keyword-extraction-master,样例目录包含以下内容:

除了README.md这个github项目默认说明文件外,目录下还有两个文件,分别是数据文件sample.txt和程序源代码文件demo-extract-keyword.ipynb。

结巴分词

我们使用的关键词提取工具为结巴分词。

之前在《如何用Python做中文分词?》一文中,我们曾经使用过该工具为中文语句做分词。这次我们使用的,是它的另一项功能,即关键词提取。

请进入终端,使用cd命令进入解压后的文件夹demo-keyword-extraction-master,输入以下命令:

pipinstall jieba

好了,软件包工具也已经准备就绪。下面我们执行

jupyternotebook

进入到Jupyter笔记本环境。

到这里,环境已经准备好了,我们下面来介绍本文使用的中文文本数据。

数据

一开始,我还曾为寻找现成的中文文本发愁。

网上可以找到的中文文本浩如烟海。

但是拿来做演示,是否会有版权问题,我就不确定了。万一把哪位大家之作拿来做了分析,人家可能就要过问一句“这电子版你是从哪里搞到的啊?”

万一再因此提出诉讼,我可无法招架。

后来发现,我这简直就是自寻烦恼——找别人的文本干什么?用我自己的不就好了?

这一年多以来,我写的文章已有90多篇,总字数已经超过了27万。

我特意从中找了一篇非技术性的,以避免提取出的关键词全都是Python命令。

我选取的,是去年的那篇《网约车司机二三事》。

这篇文章,讲的都是些比较有趣的小故事。

我从网页上摘取文字,存储到sample.txt中。

注意,这里是很容易踩坑的地方。在夏天的一次工作坊教学中,好几位同学因为从网上摘取中文文本出现问题,卡住很长时间。

这是因为不同于英语,汉字有编码问题。不同系统都有不同的默认编码,不同版本的Python接受的编码也不同。你从网上下载的文本文件,也可能与你系统的编码不统一。

不论如何,这些因素都有可能导致你打开后的文本里,到处都是看不懂的乱码。

因而,正确的使用中文文本数据方式,是你在Jupyter Notebook里面,新建一个文本文件。

然后,会出现以下的空白文件。

把你从别处下载的文本,用任意一种能正常显示的编辑器打开,然后拷贝全部内容,粘贴到这个空白文本文件中,就能避免编码错乱。

避开了这个坑,可以为你节省很多不必要的烦恼尝试。

好了,知道了这个窍门,下面你就能愉快地进行关键词提取了。

执行

回到Jupyter Notebook的主界面,点击demo-extract-keyword.ipynb,你就能看到源码了。

对,你没看错。只需要这短短的4个语句,就能完成两种不同方式(TF-idf与TextRank)的关键词提取。

本部分我们先讲解执行步骤。不同关键词提取方法的原理,我们放在后面介绍。

首先我们从结巴分词的分析工具箱里导入所有的关键词提取功能。

fromjieba.analyse import*

在对应的语句上,按下Shift+Enter组合按键,就可以执行语句,获取结果了。

然后,让Python打开我们的样例文本文件,并且读入其中的全部内容到data变量。

withopen( 'sample.txt') asf:

data = f.read()

使用TF-idf方式提取关键词和权重,并且依次显示出来。如果你不做特殊指定的话,默认显示数量为20个关键词。

forkeyword, weight inextract_tags(data, withWeight= True):

print( '%s %s'% (keyword, weight))

显示内容之前,会有一些提示,不要管它。

Building prefix dict fromthe defaultdictionary ...

Loading model fromcache / var/folders/ 8s/k8yr4zy52q1dh107gjx280mw0000gn/T/jieba.cache

Loading model cost 0.547seconds.

Prefix dict has been built succesfully.

然后列表就出来了:

优步 0 .280875594782

司机 0 .119951947597

乘客 0 .105486129485

师傅 0 .0958888107815

张师傅 0 .0838162334963

目的地 0 .0753618512886

网约车 0 .0702188986954

姐姐 0 .0683412127766

自己 0 .0672533110661

上车 0 .0623276916308

活儿 0 .0600134354214

天津 0 .0569158056792

10 0 .0526641740216

开优步 0 .0526641740216

事儿 0 .048554456767

李师傅 0 .0485035501943

天津人 0 .0482653686026

绕路 0 .0478244723097

出租车 0 .0448480260748

时候 0 .0440840298591

我看了一下,觉得关键词提取还是比较靠谱的。当然,其中也混入了个数字10,好在无伤大雅。

如果你需要修改关键词数量,就需要指定topK参数。例如你要输出10个关键词,可以这样执行:

forkeyword, weight inextract_tags(data, topK= 10, withWeight= True):

print( '%s %s'% (keyword, weight))

下面我们尝试另一种关键词提取方式——TextRank。

forkeyword, weight intextrank(data, withWeight= True):

print( '%s %s'% (keyword, weight))

关键词提取结果如下:

优步 1 .0

司机 0 .749405996648

乘客 0 .594284506457

姐姐 0 .485458741991

天津 0 .451113490366

目的地 0 .429410027466

时候 0 .418083863303

作者 0 .416903838153

没有 0 .357764515052

活儿 0 .291371566494

上车 0 .277010013884

绕路 0 .274608592084

转载 0 .271932903186

出来 0 .242580745393

出租 0 .238639889991

事儿 0 .228700322713

单数 0 .213450680366

出租车 0 .212049665481

拉门 0 .205816713637

跟着 0 .20513470986

注意这次提取的结果,与TF-idf的结果有区别。至少,那个很突兀的“10”不见了。

但是,这是不是意味着TextRank方法一定优于TF-idf呢?

这个问题,留作思考题,希望在你认真阅读了后面的原理部分之后,能够独立做出解答。

如果你只需要应用本方法解决实际问题,那么请跳过原理部分,直接看讨论吧。

原理

我们简要讲解一下,前文出现的2种不同关键词提取方式——TF-idf和TextRank的基本原理。

为了不让大家感到枯燥,这里咱们就不使用数学公式了。后文我会给出相关的资料链接。如果你对细节感兴趣,欢迎按图索骥,查阅学习。

先说TF-idf。

它的全称是 Term Frequency - inverse document frequency。中间有个连字符,左右两侧各是一部分,共同结合起来,决定某个词的重要程度。

第一部分,就是词频(Term Frequency),即某个词语出现的频率。

我们常说“重要的事说三遍”。

同样的道理,某个词语出现的次数多,也就说明这个词语重要性可能会很高。

但是,这只是可能性,并不绝对。

例如现代汉语中的许多虚词——“的,地,得”,古汉语中的许多句尾词“之、乎、者、也、兮”,这些词在文中可能出现许多次,但是它们显然不是关键词。

这就是为什么我们在判断关键词的时候,需要第二部分(idf)配合。

逆文档频率(inverse document frequency)首先计算某个词在各文档中出现的频率。假设一共有10篇文档,其中某个词A在其中10篇文章中都出先过,另一个词B只在其中3篇文中出现。请问哪一个词更关键?

给你一分钟思考一下,然后继续读。

公布答案时间到。

答案是B更关键。

A可能就是虚词,或者全部文档共享的主题词。而B只在3篇文档中出现,因此很有可能是个关键词。

逆文档频率就是把这种文档频率取倒数。这样第一部分和第二部分都是越高越好。二者都高,就很有可能是关键词了。

TF-idf讲完了,下面我们说说TextRank。

相对于TF-idf,TextRank要显得更加复杂一些。它不是简单做加减乘除运算,而是基于图的计算。

下图是原始文献中的示例图。

TextRank首先会提取词汇,形成节点;然后依据词汇的关联,建立链接。

依照连接节点的多少,给每个节点赋予一个初始的权重数值。

然后就开始迭代。

根据某个词所连接所有词汇的权重,重新计算该词汇的权重,然后把重新计算的权重传递下去。直到这种变化达到均衡态,权重数值不再发生改变。这与Google的网页排名算法PageRank,在思想上是一致的。

根据最后的权重值,取其中排列靠前的词汇,作为关键词提取结果。

如果你对原始文献感兴趣,请参考以下链接:

TF-idf原始文献链接。

TextRank原始文献链接。

TF-idf原始文献链接。

TextRank原始文献链接。

小结一下,本文探讨了如何用Python对中文文本做关键词提取。具体而言,我们分别使用了TF-idf和TextRank方法,二者提取关键词的结果可能会有区别。

你做过中文关键词提取吗?使用的是什么工具?它的效果如何?有没有比本文更高效的方法?欢迎留言,把你的经验和思考分享给大家,我们一起交流讨论。

你可能感兴趣的:(python结巴分词去掉虚词)