互联网
数学
自然语言处理
数学建模

怎么处理中文文本关键词提取和词频分布问题?

我现在有一些中文文本,我想获取这些文本的关键词。 我现在的处理是对这些文本进行分词,统计这些词的词频,按词频从高往低排序,取前N个,但是发现绝大多数是…
关注者
463
被浏览
94,225

18 个回答

看了题主关于问题的描述,我觉得从工程的角度来讲,可以分成两个阶段来做。第一个阶段,在没有用户行为数据的情况下,中文标签推荐最主要的就是如何提取文本中有效的高质量的标签。得到这些标签后,让用户用起来,然后通过用户点击行为收集数据。第二个阶段,从第一阶段得到的用户行为数据,结合从文本中得到的标签训练有监督的模型进行推荐,甚至用分类模型就有可能取得不错的效果。题主现在应该在第一阶段,那么我从文本标签或者说文本关键词提取方面来介绍一些通用流程以及方法。

简介

关于文本的关键词提取方法分为有监督、半监督和无监督三种:

有监督的关键词抽取算法是建关键词抽取算法看作是二分类问题,判断文档中的词或者短语是或者不是关键词。既然是分类问题,就需要提供已经标注好的训练预料,利用训练语料训练关键词提取模型,根据模型对需要抽取关键词的文档进行关键词抽取。

半监督的关键词提取算法只需要少量的训练数据,利用这些训练数据构建关键词抽取模型,然后使用模型对新的文本进行关键词提取,对于这些关键词进行人工过滤,将过滤得到的关键词加入训练集,重新训练模型。

无监督的方法不需要人工标注的语料,利用某些方法发现文本中比较重要的词作为关键词,进行关键词抽取。

有监督的文本关键词提取算法需要高昂的人工成本,因此现有的文本关键词提取主要采用适用性较强的无监督关键词抽取。其文本关键词抽取流程如下:


无监督文本关键词抽取流程图

无监督关键词抽取算法可以分为三大类,基于统计特征的关键词抽取、基于词图模型的关键词抽取和基于主题模型的关键词抽取。


1、基统计特征的关键词抽取算法

基于统计特征的关键词抽取算法的思想是利用文档中词语的统计信息抽取文档的关键词。通常将文本经过预处理得到候选词语的集合,然后采用特征值量化的方式从候选集合中得到关键词。基于统计特征的关键词抽取方法的关键是采用什么样的特征值量化指标的方式,目前常用的有三类:

1) 基于词权重的特征量化

基于词权重的特征量化主要包括词性、词频、逆向文档频率、相对词频、词长等。

2) 基于词的文档位置的特征量化

这种特征量化方式是根据文章不同位置的句子对文档的重要性不同的假设来进行的。通常,文章的前N个词、后N个词、段首、段尾、标题、引言等位置的词具有代表性,这些词作为关键词可以表达整个的主题。

3) 基于词的关联信息的特征量化

词的关联信息是指词与词、词与文档的关联程度信息,包括互信息、hits值、贡献度、依存度、TF-IDF值等。

我们介绍几种常用的特征值量化指标。


1.1词性

词性时通过分词、语法分析后得到的结果。现有的关键词中,绝大多数关键词为名词或者动名词。一般情况下,名词与其他词性相比更能表达一篇文章的主要思想。但是,词性作为特征量化的指标,一般与其他指标结合使用。


1.2词频

词频表示一个词在文本中出现的频率。一般我们认为,如果一个词在文本中出现的越是频繁,那么这个词就越有可能作为文章的核心词。词频简单地统计了词在文本中出现的次数,但是,只依靠词频所得到的关键词有很大的不确定行,对于长度比较长的文本,这个方法会有很大的噪音。


1.3位置信息

一般情况下,词出现的位置对于词来说有着很大的价值。例如,标题、摘要本身就是作者概括出的文章的中心思想,因此出现在这些地方的词具有一定的代表性,更可能成为关键词。但是,因为每个作者的习惯不同,写作方式不同,关键句子的位置也会有所不同,所以这也是一种很宽泛的得到关键词的方法,一般情况下不会单独使用。


1.4互信息

互信息是信息论中概念,是变量之间相互依赖的度量。互信息并不局限于实值随机变量,它更加一般且决定着联合分布 p(X,Y) 和分解的边缘分布的乘积 p(X)p(Y) 的相似程度。互信息的计算公式如下:

其中,p(x,y)是X和Y的联合概率分布函数,p(x)和p(y)分别为X和Y的边缘概率分布函数。

当使用互信息作为关键词提取的特征量化时,应用文本的正文和标题构造PAT树,然后计算字符串左右的互信息。


1.5词跨度

词跨度是指一个词或者短语字文中首次出现和末次出现之间的距离,词跨度越大说明这个词对文本越重要,可以反映文本的主题。一个词的跨度计算公式如下:

其中 last_{i} 表示词i在文本中最后出现的位置, first_{i} 表示词i在文本中第一次出现的位置,sum表示文本中词的总数。

词跨度被作为提取关键词的方法是因为在现实中,文本中总是有很多噪声(指不是关键词的那些词),使用词跨度可以减少这些噪声。


1.6 TF-IDF值

一个词的TF是指这个词在文档中出现的频率,假设一个词w在文本中出现了m次,而文本中词的总数为n,那么

一个词的IDF是根据语料库得出的,表示这个词在整个语料库中出现的频率。假设整个语料库中,包含词w的文本一共有M篇,语料库中的文本一共有N篇,则

由此可得词w的TF-IDF值为:

TF-IDF的优点是实现简单,相对容易理解。但是,TFIDF算法提取关键词的缺点也很明显,严重依赖语料库,需要选取质量较高且和所处理文本相符的语料库进行训练。另外,对于IDF来说,它本身是一种试图抑制噪声的加权,本身倾向于文本中频率小的词,这使得TF-IDF算法的精度不高。TF-IDF算法还有一个缺点就是不能反应词的位置信息,在对关键词进行提取的时候,词的位置信息,例如文本的标题、文本的首句和尾句等含有较重要的信息,应该赋予较高的权重。

基于统计特征的关键词提取算法通过上面的一些特征量化指标将关键词进行排序,获取TopK个词作为关键词。

基于统计特征的关键词的重点在于特征量化指标的计算,不同的量化指标得到的记过也不尽相同。同时,不同的量化指标作为也有其各自的优缺点,在实际应用中,通常是采用不同的量化指标相结合的方式得到Topk个词作为关键词。


2 基于词图模型的关键词抽取算法

基于词图模型的关键词抽取首先要构建文档的语言网络图,然后对语言进行网络图分析,在这个图上寻找具有重要作用的词或者短语,这些短语就是文档的关键词。

语言网络图中节点基本上都是词,根据词的链接方式不同,语言网络的主要形式分为四种:共现网络图、语法网络图、语义网络图和其他网络图

在语言网络图的构建过程中,都是以预处理过后的词作为节点,词与词之间的关系作为边。语言网络图中,边与边之间的权重一般用词之间的关联度来表示。在使用语言网络图获得关键词的时候,需要评估各个节点的重要性,然后根据重要性将节点进行排序,选取TopK个节点所代表的词作为关键词。节点的重要性计算方法有以下几种方法。


2.1综合特征法

综合特征法也叫社会网络中心性分析方法,这种方法的核心思想是节点中重要性等于节点的显著性,以不破坏网络的整体性为基础。此方法就是从网络的局部属性和全局属性角度去定量分析网络结构的拓扑性质,常用的定量计算方法如下。


2.1.1 度

节点的度是指与该节点直接向量的节点数目,表示的是节点的局部影响力,对于非加权网络,节点的度为:

对于加权网络,节点的度又称为节点的强度,计算公式为:

2.1.2 接近性

节点的接近性是指节点到其他节点的最短路径之和的倒数,表示的是信息传播的紧密程度,其计算公式为:

2.1.3 特征向量

特征向量的思想是节点的中心化测试值由周围所有连接的节点决定,即一个节点的中心化指标应该等于其相邻节点的中心化指标之线性叠加,表示的是通过与具有高度值的相邻节点所获得的间接影响力。特征向量的计算公式如下:

2.1.4 集聚系数

节点的集聚系数是它的相邻的节点之间的连接数与他们所有可能存在来链接的数量的比值,用来描述图的顶点之间阶级成团的程度的系数,计算公式如下:

2.1.5 平均最短路径

节点的平局最短路径也叫紧密中心性,是节点的所有最短路径之和的平均值,表示的是一个节点传播信息时对其他节点的依赖程度。如果一个节点离其他节点越近,那么他传播信息的时候也就越不需要依赖其他人。一个节点到网络中各点的距离都很短,那么这个点就不会受制于其他节点。计算公式如下:

因为每个算法的侧重方向的不同,在实际的问题中所选取的定量分析方法也会不一样。同时,对于关键词提取来说,也可以和上一节所提出的统计法得到的词的权重,例如词性等相结合构建词搭配网络,然后利用上述方法得到关键词。


2.2 系统科学法

系统科学法进行中心性分析的思想是节点重要性等于这个节点被删除后对于整个语言网络图的破坏程度。重要的节点被删除后会对网络的呃连通性等产生变化。如果我们在网络图中删除某一个节点,图的某些指定特性产生了改变,可以根据特性改变的大小获得节点的重要性,从而对节点进行筛选。


2.3 随机游走法

随机游走算法时网络图中一个非常著名的算法,它从给定图和出发点,随机地选择邻居节点移动到邻居节点上,然后再把现在的节点作为出发点,迭代上述过程。

随机游走算法一个很出名的应用是大名鼎鼎的PageRank算法,PageRank算法是整个google搜索的核心算法,是一种通过网页之间的超链接来计算网页重要性的技术,其关键的思想是重要性传递。在关键词提取领域, Mihalcea 等人所提出的TextRank算法就是在文本关键词提取领域借鉴了这种思想。

PageRank算法将整个互联网看作一张有向图,网页是图中的节点,而网页之间的链接就是图中的边。根据重要性传递的思想,如果一个大型网站A含有一个超链接指向了网页B,那么网页B的重要性排名会根据A的重要性来提升。网页重要性的传递思想如下图所示,

PageRank简单描述(来自PageRank论文)

在PageRank算法中,最主要的是对于初始网页重要性(PR值)的计算,因为对于上图中的网页A的重要性我们是无法预知的。但是,在原始论文中给出了一种迭代方法求出这个重要性,论文中指出,幂法求矩阵特征值与矩阵的初始值无关。

那么,就可以为每个网页随机给一个初始值,然后迭代得到收敛值,并且收敛值与初始值无关。

PageRank求网页i的PR值计算如下:

其中,d为阻尼系数,通常为0.85。

In\left( V_{i} \right) 是指向网页i的网页集合。

Out\left( V_{j} \right) 是指网页j中的链接指向的集合,

\left| Out\left( V_{j } \right) \right| 是指集合中元素的个数。


TextRank在构建图的时候将节点由网页改成了句子,并为节点之间的边引入了权值,其中权值表示两个句子的相似程度。其计算公式如下:

公式中的 w_{ji} 为图中节点 V_{i}V_{j} 的边的权重。其他符号与PageRank公式相同。

TextRank算法除了做文本关键词提取,还可以做文本摘要提取,效果不错。但是TextRank的计算复杂度很高,应用不广。


3 基于主题模型的关键词抽取

基于主题关键词提取算法主要利用的是主题模型中关于主题的分布的性质进行关键词提取。算法步骤如下:

1、从文章中获取候选关键词。即将文本分词,也可以再根据词性选取候选关键词。

2、根据大规模预料学习得到主题模型。

3、根据得到的隐含主题模型,计算文章的主题分布和候选关键词分布。

4、计算文档和候选关键词的主题相似度并排序,选取前n个词作为关键词。

算法的关键在于主题模型的构建。主题模型是一种文档生成模型,对于一篇文章,我们的构思思路是先确定几个主题,然后根据主题想好描述主题的词汇,将词汇按照语法规则组成句子,段落,最后生成一篇文章。主题模型也是基于这个思想,它认为文档是一些主题的混合分布,主题又是词语的概率分布,pLSA模型就是第一个根据这个想法构建的模型。同样地,我们反过来想,我们找到了文档的主题,然后主题中有代表性的词就能表示这篇文档的核心意思,就是文档的关键词。

pLSA模型认为,一篇文档中的每一个词都是通过一定概率选取某个主题,然后再按照一定的概率从主题中选取得到这个词语,这个词语的计算公式为:

一些贝叶斯学派的研究者对于pLSA模型进行了改进,他们认为,文章对应主题的概率以及主题对应词语的概率不是一定的,也服从一定的概率,于是就有了现阶段常用的主题模型--LDA主题模型。

LDA是D.M.Blei在2003年提出的。LDA采用了词袋模型的方法简化了问题的复杂性。在LDA模型中,每一篇文档是一些主题的构成的概率分布,而每一个主题又是很多单词构成的一个概率分布。同时,无论是主题构成的概率分布还是单词构成的概率分布也不是一定的,这些分布也服从Dirichlet 先验分布。

文档的生成模型可以用如下图模型表示:

其中 \alpha\eta 为先验分布的超参数,

\beta 为第k个主题下的所有单词的分布,

\theta 为文档的主题分布,w为文档的词,z为w所对应的主题。

Blei在论文中的图模型

LDA挖掘了文本的深层语义即文本的主题,用文本的主题来表示文本的也从一定程度上降低了文本向量的维度,很多人用这种方式对文本做分类,取得了不错的效果。具体LDA的算法在请 参考

LDA关键词提取算法利用文档的隐含语义信息来提取关键词,但是主题模型提取的关键词比较宽泛,不能很好的反应文档主题。另外,对于LDA模型的时间复杂度较高,需要大量的实践训练。


4 应用

现在阶段,文本的关键词提取在基于文本的搜索、推荐以及数据挖掘领域有着很广泛的应用。同时在实际应用中,因为应用环境的复杂性,对于不同类型的文本,例如长文本和短文本,用同一种文本关键词提取方法得到的效果并相同。因此,在实际应用中针对不同的条件环境所采用的算法会有所不同,没有某一类算法在所有的环境下都有很好的效果。

相对于上文中所提到的算法,一些组合算法在工程上被大量应用以弥补单算法的不足,例如将TF-IDF算法与TextRank算法相结合,或者综合TF-IDF与词性得到关键词等。同时,工程上对于文本的预处理以及文本分词的准确性也有很大的依赖。对于文本的错别字,变形词等信息,需要在预处理阶段予以解决,分词算法的选择,未登录词以及歧义词的识别在一定程度上对于关键词突提取会又很大的影响。

关键词提取是一个看似简单,在实际应用中却十分棘手的任务,从现有的算法的基础上进行工程优化,达观数据在这方面做了很大的努力并且取得了不错的效果。


5 总结

本文介绍了三种常用的无监督的关键词提取算法,并介绍了其优缺点。关键词提取在文本挖掘领域具有很广阔的应用,现有的方法也存在一定的问题,我们依然会在关键词提取的问题上继续努力研究,也欢迎大家积极交流。

参考文献

[1] TextRank算法提取关键词和摘要 xiaosheng.me/2017/04/08

[2] Page L, Brin S, Motwani R, et al. The PageRank citation ranking: Bringing order to the web[R]. Stanford InfoLab, 1999.

[3] 刘知远. 基于文档主题结构的关键词抽取方法研究[D]. 北京: 清华大学, 2011.

[4] tf-idf, zh.wikipedia.org/zh-han

[5] 一文详解机器领域的LDA主题模型 zhuanlan.51cto.com/art/

[6] Blei D M, Ng A Y, Jordan M I. Latent dirichlet allocation[J]. Journal of machine Learning research, 2003, 3(Jan): 993-1022.

编辑于 2018-07-03 14:26

“我”、“的”、“地”这类一般在NLP中都做为停用词处理,你可以在网上搜一下,有个1207个词的停用词表。“地震”、“四川”、“中国最强音”,这些词,你有没有发现你关注的是名词或者名词性短语?可以先做词性标注,然后再统计相关的词的词频。另外“中国最强音”应该属于新词,这个时候你需要用新词发现的一些手段去处理,比如在你统计的语料库中,如果p(中国,最强音)>>p(中国)和p(最强音),那么可以理解“中国最强音”是一个独立新词。还有很多处理这类问题的方法,可以再查查相关NLP的资料。

发布于 2013-04-23 09:24

对文章中的有效关键词进行分析,是内容推荐算法的核心。这种推荐主要是针对在文本中出现频率较高的词。但是在每篇文章中,往往出现次数最多是“的”“是”“在”等等,这些词称为“停用词”,表示对结果毫无用处,必须过滤掉的词。另外,在其他有实际意义的词中,又会遇到一些问题。比如:在《中国蜜蜂养殖》这篇文章中,“中国”“蜜蜂”“养殖”三个词出现的次数一样多,但很显然,我们更想要的标签是后面两个词。

NLPIR大数据智能语义分析平台能够实现对关键词对文章中的有用信息进行提取。

自动获取关键词的功能,大概可以分成三步

 1、通过分词算法将标题和内容分别进行分割,提取出关键词和频度。

2、将提取结果与现有词库进行比较,处理,去除无用的词得到最符合规则的关键词。这里主要就是要看词库了,我们可以自己定义词库,也可以使用现有的成熟词库。

3、在处理后的提取结果中选择适当的作为最终的关键词,得到最符合当前内容的关键词,在这个阶段就是具体情况具体分析了。

NLPIR大数据智能语义分析平台文章关键词提取系统能够在全面把握文章的中心思想的基础上,提取出若干个代表文章语义内容的词汇或短语,相关结果可用于精化阅读、语义查询和快速匹配。

发布于 2019-09-24 17:51

这个问题,使用停用词词典处理就好了,完全是可以过滤的。

另外的一种方法,可以利用词性过滤,只保留指定词性的单词即可,类似的python有jieba分词,java有hanlp,ansj-seg,这些在分词的时候都有词性的标注,都可以很方便的处理。

另外,单文本的话,感觉还是textrank提取关键词效果最好。

编辑于 2017-06-30 20:48

看这个系列,

TF-IDF与余弦相似性的应用(一):自动提取关键词

“我”、“的”、“地”的tf很高,但是idf肯定很低。

tf*idf,最后还是“地震”、“四川”、“中国最强音”胜出。

发布于 2014-01-05 12:49

需要制作一个停止词列表。中文的处理可以参照英文的处理进行转换:

文本处理的归一化过程包括:(“四归一”)

  1. 小写化(Lowercasing)消除了相同单词之间的大小写区别,帮助计算机处理相同的单词,例如 The 和 the 。
  2. 停止词(Stop word)是常用的词,如the、is、a。停止词不具有文本分析和机器学习训练的语义意义。然而,根据文本处理的最终用途,对于高级文本应用程序,为了理解相邻单词的上下文,在文本中保留停止单词可能是至关重要的。出于机器学习训练的目的,通常会删除停止词,以减少训练集中涉及的标记的数量。编程语言中有一个预定义的停止词列表,可以帮助完成这项任务。有时可以根据内容添加额外的停止词到列表中。例如,exhibit 可能经常出现在财务申报文件中,通常不是一个停止词,但在申报文件的上下文中可以被视为一个停止词。
  3. 词干分析(Stemming)是将一个词的形式转换成其基本词(base word)或词干(stem)的过程。词干分析是一种基于规则的方法,结果不一定是语言学上的感觉。词干可能与这个词的词根不同。Porter的算法是最流行的词干提取方法。例如,“analyzed”和“analyzed”这两个词的词干是“analyz”。英式英语的变体“analyzed”也会变成“analys”。词干分析可以用于解决某些单词出现频率非常低的问题
  4. 词形还原(Lemmatization)是将一个词的形式转化为其形态词根(morphological root)或词元(lemma)的过程。词形还原是一种算法,它依赖于词汇和语言结构的知识。例如,单词“analyzed”和“analyzed”的词元是“analyze”。词形还原更贵更高级。

词干分析或词形还原可以减少以各种形式出现的词的重复,保持文本数据的语义结构。词干分析在英语中比词形还原更常见,因为词干分析更简单。在文本数据中,数据稀疏性(sparseness)是指那些很少出现的单词,导致数据由许多唯一的、频率较低的标记组成。这两种技术都通过将许多稀疏出现的词聚集在相对较少稀疏的词干或词元中来降低数据稀疏性,从而有助于训练不太复杂的机器学习模型。


学习更多:

编辑于 2022-02-21 10:37

Matrix67.com

互联网时代的社会语言学:基于SNS的文本数据挖掘
今年上半年,我在人人网实习了一段时间,期间得到了很多宝贵的数据,并做了一些还算有意义的事情,在这里和大家一块儿分享。感谢人人网提供的数据与工作环境,感谢赵继承博士、詹卫东老师的支持和建议。在这项工作中,我得到了很多与众人交流的机会,特别感谢 OpenParty 、 TEDxBeijing 提供的平台。本文已发表在了《程序员》杂志,分上下两部分刊于 2012 年 7 月刊和 8 月刊,在此感谢卢鸫翔编辑的辛勤工作。由于众所周知的原因,《程序员》刊出的文章被和谐过(看到后面大家就自动地知道被和谐的内容是什么了),因而我决定把完整版发在 Blog 上,同时与更多的人一同分享。对此感兴趣的朋友可以给我发邮件继续交流。好了,开始说正文吧。
作为中文系应用语言学专业的学生以及一名数学 Geek ,我非常热衷于用计算的方法去分析汉语资料。汉语是一种独特而神奇的语言。对汉语资料进行自然语言处理时,我们会遇到很多其他语言不会有的困难,比如分词——汉语的词与词之间没有空格,那计算机怎么才知道,“已结婚的和尚未结婚的青年都要实行计划生育”究竟说的是“已/结婚/的/和/尚未/结婚/的/青年”,还是“已/结婚/的/和尚/未/结婚/的/青年”呢?这就是所谓的分词歧义难题。不过,现在很多语言模型已经能比较漂亮地解决这一问题了。但在中文分词领域里,还有一个比分词歧义更令人头疼的东西——未登录词。中文没有首字母大写,专名号也被取消了,这叫计算机如何辨认人名地名之类的东西?更惨的则是机构名、品牌名、专业名词、缩略语、网络新词等等,它们的产生机制似乎完全无规律可寻。最近十年来,中文分词领域都在集中攻克这一难关。自动发现新词成为了关键的环节。
挖掘新词的传统方法是,先对文本进行分词,然后猜测未能成功匹配的剩余片段就是新词。这似乎陷入了一个怪圈:分词的准确性本身就依赖于词库的完整性,如果词库中根本没有新词,我们又怎么能信任分词结果呢?此时,一种大胆的想法是,首先不依赖于任何已有的词库,仅仅根据词的共同特征,将一段大规模语料中可能成词的文本片段全部提取出来,不管它是新词还是旧词。然后,再把所有抽出来的词和已有词库进行比较,不就能找出新词了吗?有了抽词算法后,我们还能以词为单位做更多有趣的数据挖掘工作。这里,我所选用的语料是人人网 2011 年 12 月前半个月部分用户的状态。非常感谢人人网提供这份极具价值的网络语料。



要想从一段文本中抽出词来,我们的第一个问题就是,怎样的文本片段才算一个词?大家想到的第一个标准或许是,看这个文本片段出现的次数是否足够多。我们可以把所有出现频数超过某个阈值的片段提取出来,作为该语料中的词汇输出。不过,光是出现频数高还不够,一个经常出现的文本片段有可能不是一个词,而是多个词构成的词组。在人人网用户状态中,“的电影”出现了 389 次,“电影院”只出现了 175 次,然而我们却更倾向于把“电影院”当作一个词,因为直觉上看,“电影”和“院”凝固得更紧一些。
为了证明“电影院”一词的内部凝固程度确实很高,我们可以计算一下,如果“电影”和“院”真的是各自独立地在文本中随机出现,它俩正好拼到一起的概率会有多小。在整个 2400 万字的数据中,“电影”一共出现了 2774 次,出现的概率约为 0.000113 。“院”字则出现了 4797 次,出现的概率约为 0.0001969 。如果两者之间真的毫无关系,它们恰好拼在了一起的概率就应该是 0.000113 × 0.0001969 ,约为 2.223 × 10
-8
次方。但事实上,“电影院”在语料中一共出现了 175 次,出现概率约为 7.183 × 10
-6
次方,是预测值的 300 多倍。类似地,统计可得“的”字的出现概率约为 0.0166 ,因而“的”和“电影”随机组合到了一起的理论概率值为 0.0166 × 0.000113 ,约为 1.875 × 10
-6
,这与“的电影”出现的真实概率很接近——真实概率约为 1.6 × 10
-5
次方,是预测值的 8.5 倍。计算结果表明,“电影院”更可能是一个有意义的搭配,而“的电影”则更像是“的”和“电影”这两个成分偶然拼到一起的。
当然,作为一个无知识库的抽词程序,我们并不知道“电影院”是“电影”加“院”得来的,也并不知道“的电影”是“的”加上“电影”得来的。错误的切分方法会过高地估计该片段的凝合程度。如果我们把“电影院”看作是“电”加“影院”所得,由此得到的凝合程度会更高一些。因此,为了算出一个文本片段的凝合程度,我们需要枚举它的凝合方式——这个文本片段是由哪两部分组合而来的。令 p(x) 为文本片段 x 在整个语料中出现的概率,那么我们定义“电影院”的凝合程度就是 p(电影院) 与 p(电) · p(影院) 比值和 p(电影院) 与 p(电影) · p(院) 的比值中的较小值,“的电影”的凝合程度则是 p(的电影) 分别除以 p(的) · p(电影) 和 p(的电) · p(影) 所得的商的较小值。
可以想到,凝合程度最高的文本片段就是诸如“蝙蝠”、“蜘蛛”、“彷徨”、“忐忑”、“玫瑰”之类的词了,这些词里的每一个字几乎总是会和另一个字同时出现,从不在其他场合中使用。

光看文本片段内部的凝合程度还不够,我们还需要从整体来看它在外部的表现。考虑“被子”和“辈子”这两个片段。我们可以说“买被子”、“盖被子”、“进被子”、“好被子”、“这被子”等等,在“被子”前面加各种字;但“辈子”的用法却非常固定,除了“一辈子”、“这辈子”、“上辈子”、“下辈子”,基本上“辈子”前面不能加别的字了。“辈子”这个文本片段左边可以出现的字太有限,以至于直觉上我们可能会认为,“辈子”并不单独成词,真正成词的其实是“一辈子”、“这辈子”之类的整体。可见,文本片段的自由运用程度也是判断它是否成词的重要标准。如果一个文本片段能够算作一个词的话,它应该能够灵活地出现在各种不同的环境中,具有非常丰富的左邻字集合和右邻字集合。
“信息熵”是一个非常神奇的概念,它能够反映知道一个事件的结果后平均会给你带来多大的信息量。如果某个结果的发生概率为 p ,当你知道它确实发生了,你得到的信息量就被定义为 - log(p) 。 p 越小,你得到的信息量就越大。如果一颗骰子的六个面分别是 1 、 1 、 1 、 2 、 2 、 3 ,那么你知道了投掷的结果是 1 时可能并不会那么吃惊,它给你带来的信息量是 - log(1/2) ,约为 0.693 。知道投掷结果是 2 ,给你带来的信息量则是 - log(1/3) ≈ 1.0986 。知道投掷结果是 3 ,给你带来的信息量则有 - log(1/6) ≈ 1.79 。但是,你只有 1/2 的机会得到 0.693 的信息量,只有 1/3 的机会得到 1.0986 的信息量,只有 1/6 的机会得到 1.79 的信息量,因而平均情况下你会得到 0.693/2 + 1.0986/3 + 1.79/6 ≈ 1.0114 的信息量。这个 1.0114 就是那颗骰子的信息熵。现在,假如某颗骰子有 100 个面,其中 99 个面都是 1 ,只有一个面上写的 2 。知道骰子的抛掷结果是 2 会给你带来一个巨大无比的信息量,它等于 - log(1/100) ,约为 4.605 ;但你只有百分之一的概率获取到这么大的信息量,其他情况下你只能得到 - log(99/100) ≈ 0.01005 的信息量。平均情况下,你只能获得 0.056 的信息量,这就是这颗骰子的信息熵。再考虑一个最极端的情况:如果一颗骰子的六个面都是 1 ,投掷它不会给你带来任何信息,它的信息熵为 - log(1) = 0 。什么时候信息熵会更大呢?换句话说,发生了怎样的事件之后,你最想问一下它的结果如何?直觉上看,当然就是那些结果最不确定的事件。没错,信息熵直观地反映了一个事件的结果有多么的随机。
我们用信息熵来衡量一个文本片段的左邻字集合和右邻字集合有多随机。考虑这么一句话“吃葡萄不吐葡萄皮不吃葡萄倒吐葡萄皮”,“葡萄”一词出现了四次,其中左邻字分别为 {吃, 吐, 吃, 吐} ,右邻字分别为 {不, 皮, 倒, 皮} 。根据公式,“葡萄”一词的左邻字的信息熵为 - (1/2) · log(1/2) - (1/2) · log(1/2) ≈ 0.693 ,它的右邻字的信息熵则为 - (1/2) · log(1/2) - (1/4) · log(1/4) - (1/4) · log(1/4) ≈ 1.04 。可见,在这个句子中,“葡萄”一词的右邻字更加丰富一些。
在人人网用户状态中,“被子”一词一共出现了 956 次,“辈子”一词一共出现了 2330 次,两者的右邻字集合的信息熵分别为 3.87404 和 4.11644 ,数值上非常接近。但“被子”的左邻字用例非常丰富:用得最多的是“晒被子”,它一共出现了 162 次;其次是“的被子”,出现了 85 次;接下来分别是“条被子”、“在被子”、“床被子”,分别出现了 69 次、 64 次和 52 次;当然,还有“叠被子”、“盖被子”、“加被子”、“新被子”、“掀被子”、“收被子”、“薄被子”、“踢被子”、“抢被子”等 100 多种不同的用法构成的长尾⋯⋯所有左邻字的信息熵为 3.67453 。但“辈子”的左邻字就很可怜了, 2330 个“辈子”中有 1276 个是“一辈子”,有 596 个“这辈子”,有 235 个“下辈子”,有 149 个“上辈子”,有 32 个“半辈子”,有 10 个“八辈子”,有 7 个“几辈子”,有 6 个“哪辈子”,以及“n 辈子”、“两辈子”等 13 种更罕见的用法。所有左邻字的信息熵仅为 1.25963 。因而,“辈子”能否成词,明显就有争议了。“下子”则是更典型的例子, 310 个“下子”的用例中有 294 个出自“一下子”, 5 个出自“两下子”, 5 个出自“这下子”,其余的都是只出现过一次的罕见用法。事实上,“下子”的左邻字信息熵仅为 0.294421 ,我们不应该把它看作一个能灵活运用的词。当然,一些文本片段的左邻字没啥问题,右邻字用例却非常贫乏,例如“交响”、“后遗”、“鹅卵”等,把它们看作单独的词似乎也不太合适。我们不妨就把一个文本片段的自由运用程度定义为它的左邻字信息熵和右邻字信息熵中的较小值。

在实际运用中你会发现,文本片段的凝固程度和自由程度,两种判断标准缺一不可。只看凝固程度的话,程序会找出“巧克”、“俄罗”、“颜六色”、“柴可夫”等实际上是“半个词”的片段;只看自由程度的话,程序则会把“吃了一顿”、“看了一遍”、“睡了一晚”、“去了一趟”中的“了一”提取出来,因为它的左右邻字都太丰富了。


我们把文本中出现过的所有长度不超过 d 的子串都当作潜在的词(即候选词,其中 d 为自己设定的候选词长度上限,我设定的值为 5 ),再为出现频数、凝固程度和自由程度各设定一个阈值,然后只需要提取出所有满足阈值要求的候选词即可。为了提高效率,我们可以把语料全文视作一整个字符串,并对该字符串的所有后缀按字典序排序。下表就是对“四是四十是十十四是十四四十是四十”的所有后缀进行排序后的结果。实际上我们只需要在内存中存储这些后缀的前 d + 1 个字,或者更好地,只储存它们在语料中的起始位置。

十十四是十四四十是四十
十是十十四是十四四十是四十
十是四十
十四是十四四十是四十
十四四十是四十
是十十四是十四四十是四十
是十四四十是四十
是四十
是四十是十十四是十四四十是四十
四十
四十是十十四是十四四十是四十
四十是四十
四是十四四十是四十
四是四十是十十四是十四四十是四十
四四十是四十
这样的话,相同的候选词便都集中在了一起,从头到尾扫描一遍便能算出各个候选词的频数和右邻字信息熵。将整个语料逆序后重新排列所有的后缀,再扫描一遍后便能统计出每个候选词的左邻字信息熵。另外,有了频数信息后,凝固程度也都很好计算了。这样,我们便得到了一个无需任何知识库的抽词算法,输入一段充分长的文本,这个算法能以大致 O(n · logn) 的效率提取出可能的词来。

对不同的语料进行抽词,并且按这些词的频数从高到低排序。你会发现,不同文本的用词特征是非常明显的。下面是对《西游记》上册的抽词结果:
行者、师父、三藏、八戒、大圣、菩萨、悟空、怎么、和尚、唐僧、老孙、溃骸、什么、沙僧、太宗、徒弟、袈裟、妖精、玉帝、今日、兄弟、公主、玄奘、陛下、宝贝、性命、晓得、门外、妖魔、光蕊、观音、花果山、土地、木叉、东土、变化、变做、伯钦、判官、多少、真君、齐天大圣、蟠桃、丞相、魏征、扯住、溃骸澳、抬头、揭谛、言语、猪八戒、兵器、吩咐、安排、叩头、清风、哪吒、左右、美猴王、钉钯、孩儿、女婿、金箍棒、二郎、东西、许多、奈何、人参果、收拾、近前、太保、明月、南海、水帘洞、门首、弼马温、李天王⋯⋯
《资本论》全文:
商品、形式、货币、我们、过程、自己、机器、社会、部分、表现、没有、流通、需要、增加、已经、交换、关系、先令、积累、必须、英国、条件、发展、麻布、儿童、进行、提高、消费、减少、任何、手段、职能、土地、特殊、实际、完全、平均、直接、随着、简单、规律、市场、增长、上衣、决定、什么、制度、最后、支付、许多、虽然、棉纱、形态、棉花、法律、绝对、提供、扩大、独立、世纪、性质、假定、每天、包含、物质、家庭、规模、考察、剥削、经济学、甚至、延长、财富、纺纱、购买、开始、代替、便士、怎样、降低、能够、原料、等价物⋯⋯
《圣经》全文:
以色列、没有、自己、一切、面前、大卫、知道、什么、犹大、祭司、摩西、看见、百姓、吩咐、埃及、听见、弟兄、告诉、基督、已经、先知、扫罗、父亲、雅各、永远、攻击、智慧、荣耀、临到、洁净、离开、怎样、平安、律法、支派、许多、门徒、打发、好像、仇敌、原文作、名叫、巴比伦、今日、首领、旷野、所罗门、约瑟、两个、燔祭、法老、衣服、脱离、二十、公义、审判、十二、亚伯拉罕、石头、聚集、按着、祷告、罪孽、约书亚、事奉、指着、城邑、进入、彼此、建造、保罗、应当、摩押、圣灵、惧怕、应许、如今、帮助、牲畜⋯⋯
《时间简史》全文:
黑洞、必须、非常、任何、膨胀、科学、预言、太阳、观察、定律、运动、事件、奇点、坍缩、问题、模型、方向、区域、知道、开始、辐射、部分、牛顿、产生、夸克、无限、轨道、解释、边界、甚至、自己、类似、描述、最终、旋转、爱因斯坦、绕着、什么、效应、表明、温度、研究、收缩、吸引、按照、完全、增加、开端、基本、计算、结构、上帝、进行、已经、发展、几乎、仍然、足够、影响、初始、科学家、事件视界、第二、改变、历史、世界、包含、准确、证明、导致、需要、应该、至少、刚好、提供、通过、似乎、继续、实验、复杂、伽利略⋯⋯
哦,对了,还有我最喜欢的,《人民日报》 2000 年 4 月新闻版的抽词结果:
发展、我们、经济、主席、江泽民、领导、建设、关系、教育、干部、企业、问题、主义、政治、群众、改革、政府、思想、加强、台湾、地区、北京、总统、世界、记者、代表、民族、组织、历史、访问、原则、努力、管理、今天、技术、市场、世纪、坚持、社会主义、财政、江泽民主席、增长、积极、精神、同志、双方、自己、友好、领导干部、进一步、基础、提高、必须、不断、制度、政策、解决、取得、表示、活动、支持、通过、研究、没有、学习、稳定、举行、欢迎、农村、生活、促进、科技、投资、科学、环境、领域、公司、情况、充分⋯⋯
当然,我也没有忘记对人人网用户状态进行分析——人人网用户状态中最常出现的词是:
哈哈、什么、今天、怎么、现在、可以、知道、喜欢、终于、这样、觉得、因为、如果、感觉、开始、回家、考试、老师、幸福、朋友、时间、发现、东西、快乐、为什么、睡觉、生活、已经、希望、最后、各种、状态、世界、突然、手机、其实、那些、同学、孩子、尼玛、木有、然后、以后、学校、所以、青年、晚安、原来、电话、加油、果然、学习、中国、最近、应该、需要、居然、事情、永远、特别、北京、他妈、伤不起、必须、呵呵、月亮、毕业、问题、谢谢、英语、生日快乐、工作、虽然、讨厌、给力、容易、上课、作业、今晚、继续、努力、有木有、记得⋯⋯
事实上,程序从人人网的状态数据中一共抽出了大约 1200 个词,里面大多数词也确实都是标准的现代汉语词汇。不过别忘了,我们的目标是新词抽取。将所有抽出来的词与已有词库作对比,于是得到了人人网特有的词汇(同样按频数从高到低排序):
尼玛、伤不起、给力、有木有、挂科、坑爹、神马、淡定、老爸、卧槽、牛逼、肿么、苦逼、无语、微博、六级、高数、选课、悲催、基友、蛋疼、很久、人人网、情何以堪、童鞋、哇咔咔、脑残、吐槽、猥琐、奶茶、我勒个去、刷屏、妹纸、胃疼、飘过、考研、弱爆了、太准了、搞基、忽悠、羡慕嫉妒恨、手贱、柯南、狗血、秒杀、装逼、真特么、碎觉、奥特曼、内牛满面、斗地主、腾讯、灰常、偶遇、拉拉、屌丝、九把刀、高富帅、阿内尔卡、魔兽世界、线代、三国杀、林俊杰、速速、臭美、花痴⋯⋯

我还想到了更有意思的玩法。为什么不拿每一天状态里的词去和前一天的状态作对比,从而提取出这一天里特有的词呢?这样一来,我们就能从人人网的用户状态中提取出每日热点了!从手里的数据规模看,这是完全有可能的。我选了 12 个比较具有代表性的词,并列出了它们在 2011 年 12 月 13 日的用户状态中出现的频数(左列的数),以及 2011 年 12 月 14 日的用户状态中出现的频数(右列的数):
下雪3392那些年139146李宇春14看见145695魔兽2320高数8283生日快乐235210今天14161562北半球218脖子2369悲伤6133电磁炉03
大家可以从直觉上迅速判断出,哪些词可以算作是 12 月 14 日的热词。比方说,“下雪”一词在 12 月 13 日只出现了 33 次,在 12 月 14 日却出现了 92 次,后者是前者的 2.8 倍,这不大可能是巧合,初步判断一定是 12 月 14 日真的有什么地方下雪了。“那些年”在 12 月 14 日的频数确实比 12 月 13 日更多,但相差并不大,我们没有理由认为它是当日的一个热词。
一个问题摆在了我们面前:我们如何去量化一个词的“当日热度”?第一想法当然是简单地看一看每个词的当日频数和昨日频数之间的倍数关系,不过细想一下你就发现问题了:它不能解决样本过少带来的偶然性。 12 月 14 日“李宇春”一词的出现频数是 12 月 13 日的 4 倍,这超过了“下雪”一词的 2.8 倍,但我们却更愿意相信“李宇春”的现象只是一个偶然。更麻烦的则是“电磁炉”一行, 12 月 14 日的频数是 12 月 13 日的无穷多倍,但显然我们也不能因此就认为“电磁炉”是 12 月 14 日最热的词。
忽略所有样本过少的词?这似乎也不太好,样本少的词也有可能真的是热词。比如“北半球”一词,虽然它在两天里的频数都很少,但这个 9 倍的关系确实不容忽视。事实上,人眼很容易看出哪些词真的是 12 月 14 日的热词:除了“下雪”以外,“看见”、“北半球”和“脖子”也应该是热词。你或许坚信后三个词异峰突起的背后一定有什么原因(并且迫切地想知道这个原因究竟是什么),但却会果断地把“李宇春”和“电磁炉”这两个“异常”归结为偶然原因。你的直觉是对的—— 2011 年 12 月 14 日发生了极其壮观的双子座流星雨,此乃北半球三大流星雨之一。白天网友们不断转发新闻,因而“北半球”一词热了起来;晚上网友们不断发消息说“看见了”、“又看见了”,“看见”一词的出现频数猛增;最后呢,仰望天空一晚上,脖子终于出毛病了,于是回家路上一个劲儿地发“脖子难受”。
让计算机也能聪明地排除偶然因素,这是我们在数据挖掘过程中经常遇到的问题。我们经常需要对样本过少的项目进行“平滑”操作,以避免分母过小带来的奇点。这里,我采用的是一个非常容易理解的方法:一个词的样本太少,就给这个词的热度打折扣。为了便于说明,我们选出四个词为例来分析。
下表截取了前四个词,右边四列分别表示各词在 12 月 13 日出现的频数,在 12 月 14 日出现的频数,在两天里一共出现的总频数,以及后一天的频数所占的比重。第三列数字是前两列数字之和,第四列数字则是第二列数字除以第三列数字的结果。最后一列应该是一个 0 到 1 之间的数,它表明对应的词有多大概率出现在了 12 月 14 日这一天。最后一列可以看作是各词的得分。可以看到,此时“下雪”的得分低于“李宇春”,这是我们不希望看到的结果。“李宇春”的样本太少,我们想以此为缘由把它的得分拖下去。
下雪33921250.736那些年1391462850.512李宇春1450.8看见1456958400.827(平均)313.750.719
怎么做呢?我们把每个词的得分都和全局平均分取一个加权平均!首先计算出这四个词的平均总频数,为 313.75 ;再计算出这四个词的平均得分,为 0.719 。接下来,我们假设已经有 313.75 个人预先给每个词都打了 0.719 分,换句话说每个词都已经收到了 313.75 次评分,并且所有这 313.75 个评分都是 0.719 分。“下雪”这个词则还有额外的 125 个人评分,其中每个人都给了 0.736 分。因此,“下雪”一词的最终得分就是:
下雪(0.736 × 125 + 0.719 × 313.75) / (125 + 313.75) ≈ 0.724
类似地,其他几个词的得分依次为:
那些年(0.512 × 285 + 0.719 × 313.75) / (285 + 313.75) ≈ 0.62李宇春(0.8 × 5 + 0.719 × 313.75) / (5 + 313.75) ≈ 0.7202看见(0.827 × 840 + 0.719 × 313.75) / (840 + 313.75) ≈ 0.798
容易看出,此时样本越大的词,就越有能力把最终得分拉向自己本来的得分,样本太小的词,最终得分将会与全局平均分非常接近。经过这么一番调整,“下雪”一词的得分便高于了“李宇春”。实际运用中, 313.75 这个数也可以由你自己来定,定得越高就表明你越在意样本过少带来的负面影响。这种与全局平均取加权平均的思想叫做 Bayesian average ,从上面的若干式子里很容易看出,它实际上是最常见的平滑处理方法之一——分子分母都加上一个常数——的一种特殊形式。
利用之前的抽词程序抽取出人人网每一天内用户状态所含的词,把它们的频数都与前一天的作对比,再利用刚才的方法加以平滑,便能得出每一天的热词了。我手上的数据是人人网 2011 年 12 月上半月的数据,因此我可以得出从 12 月 2 日到 12 月 15 日的热词(选取每日前 5 名,按得分从高到低)。
2011-12-02:第一场雪、北京、金隅、周末、新疆
2011-12-03:荷兰、葡萄牙、死亡之组、欧洲杯、德国
2011-12-04:那些年、宣传、期末、男朋友、升旗
2011-12-05:教室、老师、视帝、体育课、质量
2011-12-06:乔尔、星期二、摄影、经济、音乐
2011-12-07:陈超、星巴克、优秀、童鞋、投票
2011-12-08:曼联、曼城、欧联杯、皇马、冻死
2011-12-09:保罗、月全食、交易、火箭、黄蜂
2011-12-10:变身、罗伊、穿越、皇马、巴萨
2011-12-11:皇马、巴萨、卡卡、梅西、下半场
2011-12-12:淘宝、阿内尔卡、双十二、申花、老师
2011-12-13:南京、南京大屠杀、勿忘国耻、默哀、警报
2011-12-14:流星雨、许愿、愿望、情人节、几颗
2011-12-15:快船、保罗、巴萨、昨晚、龙门飞甲
看来, 12 月 14 日果然有流星雨发生。
注意,由于我们仅仅对比了相邻两天的状态,因而产生了个别实际上是由工作日/休息日的区别造成的“热词”,比如“教室”、“老师”、“星期二”等。把这样的词当作热词可能并不太妥。结合上周同日的数据,或者干脆直接与之前整个一周的数据来对比,或许可以部分地解决这一问题。
事实上,有了上述工具,我们可以任意比较两段不同文本中的用词特点。更有趣的是,人人网状态的大多数发布者都填写了性别和年龄的个人信息,我们为何不把状态重新分成男性和女性两组,或者 80 后和 90 后两组,挖掘出不同属性的人都爱说什么?要知道,在过去,这样的问题需要进行大规模语言统计调查才能回答!然而,在互联网海量用户生成内容的支持下,我们可以轻而易举地挖掘出答案来。
我真的做了这个工作(基于另一段日期内的数据)。男性爱说的词有:
兄弟、篮球、男篮、米兰、曼联、足球、蛋疼、皇马、比赛、国足、超级杯、球迷、中国、老婆、政府、航母、踢球、赛季、股市、砸蛋、牛逼、铁道部、媳妇、国际、美国、连败、魔兽、斯内德、红十字、经济、腐败、程序、郭美美、英雄、民主、鸟巢、米兰德比、官员、内涵、历史、训练、评级、金融、体育、记者、事故、程序员、媒体、投资、事件、社会、项目、伊布、主义、决赛、操蛋、纳尼、领导、喝酒、民族、新闻、言论、和谐、农民、体制、城管⋯⋯
下面则是女性爱说的词:
一起玩、蛋糕、加好友、老公、呜呜、姐姐、嘻嘻、老虎、讨厌、妈妈、呜呜呜、啦啦啦、便宜、减肥、男朋友、老娘、逛街、无限、帅哥、礼物、互相、奶茶、委屈、各种、高跟鞋、指甲、城市猎人、闺蜜、巧克力、第二、爸爸、宠物、箱子、吼吼、大黄蜂、狮子、胃疼、玫瑰、包包、裙子、游戏、遇见、嘿嘿、灰常、眼睛、各位、妈咪、化妆、玫瑰花、蓝精灵、幸福、陪我玩、任务、怨念、舍不得、害怕、狗狗、眼泪、温暖、面膜、收藏、李民浩、神经、土豆、零食、痘痘、戒指、巨蟹、晒黑⋯⋯
下面是 90 后用户爱用的词:
加好友、作业、各种、乖乖、蛋糕、来访、卧槽、通知书、麻将、聚会、补课、欢乐、刷屏、录取、无限、互相、速度、一起玩、啦啦啦、晚安、求陪同、基友、美女、矮油、巨蟹、五月天、第二、唱歌、老虎、扣扣、啧啧、帅哥、哈哈哈、尼玛、便宜、苦逼、斯内普、写作业、劳资、孩纸、哎哟、炎亚纶、箱子、无聊、求来访、查分、上课、果断、处女、首映、屏蔽、混蛋、暑假、吓死、新东方、组队、下学期、陪我玩、打雷、妹纸、水瓶、射手、搞基、吐槽、同学聚会、出去玩、呜呜、白羊、表白、做作业、签名、姐姐、停机、伏地魔、对象、哈哈、主页、情侣、无压力、共同、摩羯、碎觉、肿么办⋯⋯
下面则是 80 后用户爱用的词:
加班、培训、周末、工作、公司、各位、值班、砸蛋、上班、任务、公务员、工资、领导、包包、办公室、校内、郭美美、时尚、企业、股市、新号码、英国、常联系、实验室、论文、忙碌、项目、部门、祈福、邀请、招聘、顺利、朋友、红十字、男朋友、媒体、产品、标准、号码、存钱、牛仔裤、曼联、政府、简单、立秋、事故、伯明翰、博士、辞职、健康、销售、深圳、奶茶、搬家、实验、投资、节日快乐、坚持、规则、考验、生活、体制、客户、发工资、忽悠、提供、教育、处理、惠存、沟通、团购、缺乏、腐败、启程、红十字会、结婚、管理、环境、暴跌、服务、变形金刚、祝福、银行⋯⋯
不仅如此,不少状态还带有地理位置信息,因而我们可以站在空间的维度对信息进行观察。这个地方的人都爱说些什么?爱说这个词的人都分布在哪里?借助这些包含地理位置的签到信息,我们也能挖掘出很多有意思的结果来。例如,对北京用户的签到信息进行抽词,然后对于每一个抽出来的词,筛选出所有包含该词的签到信息并按地理坐标的位置聚类,这样我们便能找出那些地理分布最集中的词。结果非常有趣:“考试”一词集中分布在海淀众高校区,“天津”一词集中出现在北京南站,“逛街”一词则全都在西单附近扎堆。北京首都国际机场也是一个非常特别的地点,“北京”、“登机”、“终于”、“再见”等词在这里出现的密度极高。
从全国范围来看,不同区域的人也有明显的用词区别。我们可以将全国地图划分成网格,统计出所有签到信息在各个小格内出现的频数,作为标准分布;然后对于每一个抽出来的词,统计出包含该词的签到信息在各个小格内出现的频数,并与标准分布进行对比(可以采用余弦距离等公式),从而找出那些分布最反常的词。程序运行后发现,这样的词还真不少。一些明显具有南北差异的词,分布就会与整个背景相差甚远。例如,在节假日的时候,“滑雪”一词主要在北方出现,“登山”一词则主要在南方出现。地方特色也是造成词语分布差异的一大原因,例如“三里屯”一词几乎只在北京出现,“热干面”一词集中出现在武汉地区,“地铁”一词明显只有个别城市有所涉及。这种由当地人的用词特征反映出来的真实的地方特色,很可能是许多旅游爱好者梦寐以求的信息。另外,方言也会导致用词分布差异,例如“咋这么”主要分布在北方地区,“搞不懂”主要分布在南方城市,“伐”则非常集中地出现在上海地区。当数据规模足够大时,或许我们能通过计算的方法,自动对中国的方言区进行划分。
其实,不仅仅是发布时间、用户年龄、用户性别、地理位置这四个维度,我们还可以对浏览器、用户职业、用户活跃度、用户行为偏好等各种各样的维度进行分析,甚至可以综合考虑以上维度,在某个特定范围内挖掘热点事件,或者根据语言习惯去寻找出某个特定的人群。或许这听上去太过理想化,不过我坚信,有了合适的算法,这些想法终究会被一一实现。
编辑于 2013-04-22 12:45
《构建企业级推荐系统》作者,公众号「数据与智能」主理人,9年推荐系统实战经验,持续输出推荐系统、大数据、机器学习、AI等硬核技术文章


在使用文本训练统计算法之前,你需要执行一些预处理任务,例如文本清理,语音标记,停用词删除,词干,词形去除等。


在本章中,你将看到如何使用Python执行文本清理和操作。在使用文本执行各种任务之前,你通常需要执行自定义文本清理和操作。例如,你可能想在执行文本分类之前删除所有特殊字符。或者,你可能只想在文本中保留数字。


在Python中,文本被视为字符串类型。因此,可以将诸如Regex之类的字符串操作库用于文本清理和操作。此外,你可以使用默认的字符串函数来清理和操作字符串。在本章中,你将看到两种方法。


1 .正则表达介绍


正则表达式,也称为Regex,是一个字符序列,用于匹配某些文本内的字符串模式。匹配模式后,你可以在该模式上应用不同的功能。例如,你可以替换字符串上的值,并且根据正则表达式模式,可以在文本中添加或删除值,可以在文本内部搜索值,等等。在本节中,你将学习一些最有用的python中的regex表达式。


以下脚本将regex模块导入到你的Python应用程序中。


2. 在文本中的查询以及匹配一些格式


要在字符串中搜索一种格式,你可以使用搜索或匹配函数。我们先来看看如何使用match函数。


让我们赋予一个变量 “sentence”一个文本:



接下来,我们将定义一个正则表达式模式,并检查句子变量中文本的哪一部分与正则表达式所含的格式匹配。


在上面的脚本中,我们定义了一个可以匹配任何字符串的正则表达式模式“.*”。如果打印输出,你应该看到以下文本。文本包含匹配的字符串、匹配的字符索引(即跨度)和匹配的对象。


要输出匹配的字符串,可以使用返回的正则表达式对象的 group(0) 属性,如下所示:


从输出中,你可以看到整个字符串已匹配。这是因为“.*”表达式匹配任何字符串,即使字符串为空,如下所示:


输出再次返回匹配项,即空字符串。


如果要匹配所有长度至少为 1 或包含 1 个字符的字符串,可以使用“.+”正则表达式,如下所示:


现在,存储在sentence 变量中的空字符串没有匹配上。


接下来,让我们匹配字符串中所有的字母。使用的模式是“[a-zA-Z ]”,这意味着匹配从 a 到 z 的小写字母,匹配从 A 到 Z 的大写字母,也匹配单个空格。这是脚本。


输出如下:


match 函数只匹配从头开始的字符串。如果在字符串的开头找不到匹配项,则 match 函数返回 none。例如,以下示例中的 match 函数将返回 none,因为字符串以数字开头,而 match 函数中的正则表达式模式搜索字母。


为了解决上面脚本中解释的问题,我们就要使用搜索功能。搜索函数不仅会在字符串的开头查找正则表达式模式,还会在字符串中间任何位置查找。以下正则表达式模式将跳过字符串开头的整数并返回剩余的文本。


3 .字符串中的文本取代


要替换字符串中的文本,请使用 Regex 模块中的子函数。例如,以下脚本将句子字符串中的 2018 替换为 1998。


类似地,以下脚本替换从 a 到 f 的所有小写字母,并用星号替换它们。

4.从字符串中去除数字和字母


该替代函数还可用于从字符串中删除数字、字母或特殊字符。你所要做的就是指定一个正则表达式模式,它可以找到你要删除的字母或数字,并用一个没有空格的空字符串替换它们。


以下脚本查找所有数字并用空字符串替换它们。在输出中,你将看到数字已被删除。注意:查找数字的正则表达式模式是 \d。


有时,删除一个字母表会导致一个没有意义的字母表。例如,在以下示例中,字符串末尾有一个“a”。为了删除这样的字母,使用了正则表达式“\s+[a-zA-Z]\+s”。这是一个例子。

以下脚本用于删除所有字母。这里,指定的正则表达式是 [a–z]。属性“flags = re.I”用于删除区分大小写。因此,大写和小写字母都被空格替换。


去掉字母会产生多个空格,如下图:


让我们看看如何删除多个空格。



5 .从字符串中去除空格


要去除文本中的空格,你需要用一个没有空格的空字符串替换空格,如图下:


6. 从字符串中去掉特殊符号


特殊字符是字母和数字以外的符号,例如@、/、*、& 等。在使用文本之前,你通常需要从文本中删除所有特殊字符。查找除特殊字符以外的所有内容的模式是 \w。你可以通过反转 \w 来选择特殊字符。“^”运算符用于反转正则表达式。因此,正则表达式“[\^w]”表示仅选择特殊字符。接下来,你可以用空格替换特殊字符。


类似地,以下正则表达式匹配除大小写字母和 1-9 数字之外的所有内容,这会留下特殊字符。然后用空字符串替换特殊字符。



7. 其他字符串函数


除了正则表达式,Python 还包含一些用于字符串操作的默认函数。在本章中,你将看到其中一些函数。


7.1字符串长度


字符串长度是指字符串中的字符数。len() 函数用于查找字符串的长度。


7.2 字符串连接


连接两个或多个字符串的最简单方法是通过加法运算符,如下例所示。


7.3 找到字符串的开头和结尾


要查找字符串是否以特定子字符串开头,你可以使用 startswith() 函数。


类似地,要查找字符串是否以特定子字符串结尾,可以使用endswith() 函数。


7.4 改变字符串大小写


你可以分别使用lower() 和upper() 函数将字符串转换为小写和大写。


以下脚本将字符串转换为小写。


同样,下面的脚本将字符串转换为大写。


7.5 从字符串中找到子字符串


要查找一个字符串是否存在于另一个字符串中,你可以使用“in”运算符,如以下两个示例所示。如果在另一个字符串中找到子字符串,则 in 运算符返回 True,如果另一个字符串中不存在子字符串,则返回 false。


这是在另一个字符串中找到子字符串的示例。


以下示例显示当在另一个字符串中找不到子字符串时,“in”运算符返回 false。


7.6 拆分字符串


在 Python 中,split() 函数用于拆分字符串。字符串中要用作分割字符串的分隔符的字符将作为参数传递给 split() 函数。如果你没有将任何参数值传递给 split() 函数,则字符串将被空格 split() ,如下所示:




延展阅读-正则以及Python字符串函数

要进一步了解如何使用正则表达式进行文本清理和操作,请查看 Python 中正则表达式的官方文档: docs.python.org/3/libra

同样,要深入了解 Python 的默认字符串函数,请查看 Python 字符串函数的官方文档: docs.python.org/2.5/lib


了解更多推荐系统、大数据、机器学习、AI等硬核技术,可以关注我的知乎,或同名微信公众号

发布于 2021-09-30 14:55

提取关键词,方法非常多。

先看你是单文档还是多文档。

如果是单文档,用textrank,另外你需要注意停用词处理。或者把单文档中按段或句分割成多文档

如果是多文档,那就更简单了,tf-idf是最简单的,也可用lda, 词嵌入svd,w2v,获取文档语义,然后找出与文档语义相关度最大的几个词就可

发布于 2015-10-10 18:41

糖果云提供一篇文章到几个G文本的词频统计功能,字频分析与词频分析是分隔的。

糖果云: www.tgyun.cc

红楼梦的词频分析:

曹禺《雷雨》库排名前100的词频统计

发布于 2017-11-15 10:26
【Python与seo应用实战】有道反爬问题(未解决)
292 播放
更多,更全的【Python与seo应用实战】视频关注我,私聊我!
编辑于 2021-12-24 14:22· 131 次播放
既快又准,功能强大电脑软件!通过文本内容来查找出文档位置
3796 播放 · 3 赞同
它可以通过文本内容来查找出文档位置,并且搜索的速度非常快。只要你输入关键字,它可以在1秒钟内帮你找到文本文件。 软件完全免费,操作起来也简单。 软件除了搜索功能外,还有翻译功能!在最上方的工具栏中,点击翻译功能后,再点击“设置”按钮选择语言。 选择语言后不要直接点“确定”,选择语言后点击“>”按钮,当前语言中出现了你选择的语言,再点击“确认”。 接下来我们将文本复制进框框中,软件就会自动进行翻译。
发布于 2022-03-16 09:05· 818 次播放

你的分词工具,有标注词性吗?把某些词性和常见的停词都屏蔽了即可。

发布于 2015-08-05 17:54

词与题目的相关性,词的出现频率

发布于 2022-02-21 17:50

一是你的语料库

二是光用df不行吧,一般用tf*idf提取特征向量

发布于 2013-04-20 16:37

个人感觉可以试试语料库检索工具,把文本导入进去,加载好停用词表。这些工作做好后,再选择对照文本,进行目标语料文本的关键词分析、获取词频。

顺带推荐 AntConc 和 YiCorpus 这两种语料库检索工具。

前者是一款语料库检索软件,不能对文本进行分词处理,不过既然现有文本已经分词过了也就无所谓了;后者是在线多功能语料库检索分析平台,界面简洁,易上手一些。

可以分别试试:

Laurence Anthony's AntConc

YiCorpus

发布于 2023-09-06 08:41

正好刚学到这个问题的现成算法。

在 人民日报玩微博:一个文本分析小作业中,经过 用Python BeautifulSoup爬取,得到人民日报微博账号下的所有内容。

这就是本文分析的一个素材了,比如我在这堆内容中,筛选出了所有标题中带3个及以上感叹号的,想看看到底都是些什么厉害事情, 得用那么强烈的语气来讲。

瞥一眼就知道这是一份令人激动的文档

任务:提取这些标题中的关键词。

用的就是jieba,有两个方式:

一是用jieba分词,然后统计词频,提取高频词,并且后面还能直接用这个分词结果,继续进行话题模型和情感分析;

二是用jieba.analyse可以直接取出关键词,这里面又有两种抽取方式。

所以下面会有三段代码。

1、分词

这里用到的“中文停用词表”来自网络,一搜还挺多的。

#读取原文本到OriginText,类型为列表,原文一行为一个元素
with open('title_exclamatory_3.txt',encoding='utf-8') as file:
    OriginText = file.readlines()  
file.close()

#清洗文本,读取OriginText列表,删除空字符,将清洗后的文本赋值给新的列表text
import re
text = []
for line in OriginText:
    line = re.sub(r'[A-Za-z0-9①-⑨]','',line)#删除数字和字母
    line = re.sub(r'[,。!?、—“”‘’·【】#|↓():;.…:/]+','',line)#删除符号
    text.append(line)
#print(text)

#一个元素一行,将text(即清理后的文本)输出到本地文件 
f = open('title_exclamatory_3_new.txt','w',encoding='utf-8')
for i in text:
    f.write(i+'\n')
f.close()

#调出停用词表
def stopwordslist(filepath):
    stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf_8').readlines()]
    return stopwords
stopwords = stopwordslist("stopwords-master/cn_stopwords.txt")

#拿刚才清理后的文本来分词,并删除停用词
import jieba
CutResult = []   
for line in text: 
    for i in jieba.cut(line):
        if i not in stopwords:
            CutResult.append(i)
#print(CutResult)

#一词一空格,输出到本地文件 
f = open('title_exclamatory_3_keywords.txt','w',encoding='utf-8')
for i in CutResult:
    f.write(i+' ')   
f.close()

得到一个分完词的文档,上图中的标题分完词长这样。

2、基于TF-IDF算法的关键词抽取

这个抽取关键词的基本思想,竟然也被我看懂了,说明确实非常直接,又正好击中这个提问中的要害。

TF-IDF算法总的思想就是用词频来衡量一个词的重要性,其中:

TF (term frequency ):词频,就是该词在文档中出现的次数;

IDF ( inverse document frequency ):逆文档频率,需要一个语料库(corpus)来模拟语言的使用环境,看该词在语料库中的出现频率。

字词的重要性,随着它在文档中出现的次数增加而增加,但同时随着它在语料库中出现的频率增加而下降。

自动提取关键词的算法,就是计算出文档中每个词的TF-IDF值,然后按降序排列,取排在最前面的N个词(N可以自定义),这样就既考虑了出现频次,又过滤掉了“的”“地”“得”这些常用词。

以下代码就直接把词频统计也做好了。

import pandas as pd
import jieba.analyse

rows=pd.read_csv('title_exclamatory_3.csv', encoding='utf-8',dtype=str)
segments = []
for index, row in rows.iterrows(): #遍历DataFrame每行,返回每行的索引及一个包含行本身的对象
    content = row[0]
    #关键词抽取,topK为返回几个TF/IDF权重最大的关键词,allowPOS仅包括指定词性的词:'ns'地名、'n'普通名词、'vn'名动词、'v'普通动词
    words = jieba.analyse.extract_tags(content, topK=50, allowPOS=('ns', 'n', 'vn', 'v'))
    #print(words)
    for word in words:
        segments.append({'word':word, 'count':1})
dfSeg = pd.DataFrame(segments)
dfWord = dfSeg.groupby('word')['count'].sum()
dfWord.to_csv('title_exclamatory_3_keyword.csv',encoding='utf_8_sig')

3、基于TextRank算法的关键词抽取

这个基本思路就果然没有看懂,但代码几乎是一样的,就是把jieba.analyse.extract_tags改成jieba.analyse.textrank——

import pandas as pd
import jieba.analyse

rows=pd.read_csv('title_exclamatory_3.csv', encoding='utf-8',dtype=str)
segments = []
for index, row in rows.iterrows(): #遍历DataFrame每行,返回每行的索引及一个包含行本身的对象
    content = row[0]
    #关键词抽取,topK为返回几个权重最大的关键词,allowPOS仅包括指定词性的词:'ns'地名、'n'普通名词、'vn'名动词、'v'普通动词
    words = jieba.analyse.textrank(content, topK=50, allowPOS=('ns', 'n', 'vn', 'v'))
    #print(words)
    for word in words:
        segments.append({'word':word, 'count':1})
dfSeg = pd.DataFrame(segments)
dfWord = dfSeg.groupby('word')['count'].sum()
dfWord.to_csv('title_exclamatory_3_keywords.csv',encoding='utf_8_sig')

基于TF-IDF算法和基于TextRank算法提取出来的关键词,在最终词频统计结果上稍有不同,但咱不懂原理就确实不懂为啥不同了。

但轻微差异不影响我们能看出,需要疯狂使用3个及以上感叹号的,多是体育比赛相关内容,情绪那么激动也能理解了;同样的过程再跑一遍所有带感叹号的标题,就能看出官微情绪一激动,就必然要引导转发了。

分词之后还可以画词云、建主题模型:

Python wordcloud & stylecloud以及Tableau绘制词云

Python gensim生成LDA主题模型

编辑于 2022-02-17 19:01

去停用词 是几乎所有文本处理分析第一个步骤

发布于 2016-03-09 16:12
( 为什么?)