很多场合我们需要用简短的几句话来说明一篇文章的中心思想,用几个关键词来说明文章的主题。如果你写过论文的话,一定会对这些十分熟悉。一篇好的论文精炼的摘要和正确的关键词是必不可少的。这种提取关键词这种又枯燥又麻烦的事情肯定得教给计算机来做。当然是用的是我最爱的Python编程语言啦。
1 出现频率最高的词语
很容易想到的是根据词语出现的频率来排序,出现次数多的词语就是关键词啦。碰到的第一个问题是如何将一大篇文章,分成一个一个词语,因为中文里词语是没有明显间隔的。这个问题,这里我不作讨论,Python的jieba中文分词包就能很好地做这个事情。使用起来也非常简单:
import jieba list(jieba.cut(\'国际奥委会评估团昨日在京召开新闻发布会,评估团主席茹科夫评价此次考察的相关情况时说,北京“有能力成功举办2022年冬奥会”。\')) #cut返回的结果是一个generator,用list便可将其转换为列表
[\'国际奥委会\', \'评估\', \'团\', \'昨日\', \'在\', \'京\', \'召开\', \'新闻\', \'发布会\', \',\', \'评估\', \'团\', \'主席\', \'茹科夫\', \'评价\', \'此次\', \'考察\', \'的\', \'相关\', \'情况\', \'时说\', \',\', \'北京\', \'“\', \'有\', \'能力\', \'成功\', \'举办\', \'2022\', \'年\', \'冬奥会\', \'”\', \'。\']
是不是很赞,各种名词都被识别了出来。那接下来我们就试一下吧。
文章内容来自这个网页 http://news.sohu.com/20150329/n410476532.shtml
import jieba from collections import Counter words = jieba.cut(text) freq = Counter(words) #Counter正如其名字,就是统计列表中各个元素出现次数的 common = freq.most_common(20) #返回出现数目最多的20个关键词
[(\',\', 94), (\'的\', 78), (\'\n\', 67), (\'\u3000\', 66), (\'。\', 50), (\'了\', 30), (\'北京\', 27), (\'和\', 25), (\'年\', 24), (\'评估\', 21), (\'我们\', 17), (\'在\', 16), (\'冬奥会\', 16), (\'将\', 15), (\'国际奥委会\', 15), (\'、\', 12), (\'也\', 12), (\'团\', 11), (\'”\', 11), (\'“\', 11)]
这里我们先瞅一瞅,出现最多的到底是什么,可以看到算法成功地发现了国际奥委会、北京、冬奥会这些关键词,无疑是文章的一个主题。但其他的好像都没有什么关系诶。出现次数最多的是标点符号,也毫不让人感到意外,毕竟每一句话几乎都有一个逗号。这样虽然找到的关键词,但效率太低了,10个才中了一两个。
除了标点符号外,我们还找到了一些没有意义的副词、代词等,这写都是不应该出现在关键词里的。
2 过滤标点符号
这解决起来也很简单,副词和标点符号基本上都是落单的,过滤掉一个字的词就行了,仔细想想现代中文里,一个字基本上都没有明确的含义,这样做也不会犯什么大错。
这个只需要在Python里加一行就行了
words = filter(lambda x:len(x)>1,words)
filter这个函数会一次遍历words列表里的每一个元素,将其作为参数输入到filter的第一个参数里。第一个参数必须是一个函数,在这里是一个简单的匿名函数(及没有名字),匿名函数适合这种简单的功能。lambda关键词后是匿名函数的参数x,冒号后边便是返回值。在这里返回值是True或False,如果x的长度大于1就会就会返回True,反之返回False。更进一步说filter的第一个参数必须是这种返回True或False的函数。遍历words列表的元素过程中,如果输入到lambda函数返回True就会继续留在列表里,反之就会被踢出去。一行代码,多么凝练地实现了我们所需要的功能。
这时关键词就已经有很大的改观了:
[(\'北京\', 27), (\'评估\', 21), (\'我们\', 17), (\'冬奥会\', 16), (\'国际奥委会\', 15), (\'2022\', 9), (\'举办\', 8), (\'考察\', 8), (\'王安顺\', 8), (\'微克\', 7)]
但我们仍然不能忍受\'我们\',这种没有意义的词出现在关键词里。
3 过滤停用词
要解决这个问题,最简单的方式是列一个表,囊括所有这种没有意义的词语。这种词语有一个专门的名字,叫做停用词(stop words)。很容易在网上找到这样一个表,包含1000个停用词的表就足够了。后面我会一起贴出来。
STOPWORDS = []
with open(\'stopwords_zh.txt\',\'r\',encoding=\'utf-8\') as fh:
for w in fh:
STOPWORDS.append(w.strip())
words = jieba.cut(text)
words = filter(lambda x:len(x)>1 and x not in STOPWORDS, words)
freq = Counter(words)
common = freq.most_common(10)
这时我们就成功地去掉了,
[(\'北京\', 27), (\'评估\', 21), (\'冬奥会\', 16), (\'国际奥委会\', 15), (\'2022\', 9), (\'考察\', 8), (\'举办\', 8), (\'王安顺\', 8), (\'微克\', 7), (\'2008\', 7)]
看起来已经非常不错了。
附 中文停用词