1,本Notebook背景介绍 此前介绍了一篇论文范例《基于科技政策文本的程度词典构建研究》,该文尝试利用词典法辨识和量化我国科技政策文本用语中蕴含的决策者态度及其强弱程度,并且结合 TextRank算法进行实验验证。 那么这个textRank算法到底是怎样的, 今天这个Notebook,使用简单的新闻文本测试数据,对textRank算法计算进行测试。 后续我们会结合GooSeeker文本分词和情感分析软件的分词和文本分析结果,做实际的关键词提取对比实验。 1.1,什么是TextRank TextRank算法是由网页重要性排序算法PageRank算法迁移而来的,PageRank算法根据互联网页面之间的链接关系计算每个页面的重要性。PageRank算法的使用方法,可以参考前几天我们发布的一篇在Jupyter Notebook下做PageRank算法测试的文章:在Jupyter Notebook中用Python做PageRank算法计算。更详细的解释参见PageRank算法详解。 TextRank 算法是一种用于文本的基于图的排序算法,其基本思想来源于谷歌的 PageRank 算法。该算法先把文本分割成若干子单元 (如单词、句子) 并建立图模型,再利用投票机制对文本中的重要成分进行排序,仅利用单篇文档本身的信息即可实现关键词提取、摘要生成等功能。最早提出 TextRank 方法的是北得克萨斯州大学的 Rada Mihalcea 和 Paul Tarau,在名为 TextRank: Bringing Order into Texts 的论文里,他们不仅仅论述了怎么利用 TextRank 去高效准确的提取关键词和关键句子,并且实证了 TextRank 相比于其他一些更古老的方法有更高的准确性。 和 LDA、HMM 等模型不同,TextRank算法不需要事先对多篇文档进行学习训练, 这个简洁的特性使其得到了广泛的应用。对于关键词提取,主要是要找出词与词之间的联系,也就是词的共现关系。作为对比,可看到我们此前发布的3篇关于LDA算法的Jupyter Notebook,例如:微博内容分词后怎样用JupyterNotebook做LDA主题模型分析。 对于TextRank问题,可以设置一个窗口k。 {w1,w2,w3......wk}对于在滑动窗口k之内的词,都可以认为是有联系的,对于有联系的两个词,可以在有词构成的图中增加相应的权重。 一个窗口遍历完文章的所有句子后,一个由词语构成的图就建立了。 1.2,测试数据 我们从网页上摘取这样一段新闻: 国家发改委表示,目前来看,两轮储备投放基本实现了预期目标,社会各界普遍反映,储备投放体现了国家确保大宗商品市场供应和价格稳定的决心信心,引导了价格预期,缓解了部分行业企业的原材料成本压力。下一步,我们还将持续关注大宗商品价格走势情况,统筹利用好国内国外两种资源,综合采取多种措施,包括加大增产增供、适时储备投放、加强进出口调节、加大市场监管力度等,切实做好大宗商品保供稳价工作。 为简化测试,对新闻文本片段做处理后,以数组的形式存储: [['国家发改委','表示','目前','两轮','储备投放','基本','实现','预期','目标','社会','各界','普遍','反映','储备投放','体现','国家','确保','大宗','商品','市场','供应','价格','稳定','决心','信心','引导','价格','预期','缓解','部分','行业','企业','原材料','成本','压力','','持续','关注','大宗商品','价格','走势','情况','统筹','利用','国内','国外','两种','资源','综合','采取','多种','措施','加大','增产','增供','适时','储备投放','加强','进出口','调节','加大','市场','监管','力度','切实','大宗商品','保供','稳价','工作']] 1.3,本notebook所做的测试 基于测试数据,在Jupyter Notebook中使用Python做TextRank提取关键词测试。 代码参考了Github上的textRank代码 2,引入numpy库 Numpy是一个常用的Python科学技术库,通过它可以快速对数组进行操作,包括形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等。许多Python库和科学计算的软件包都使用Numpy数组作为操作对象,或者将传入的Python数组转化为Numpy数组,因此在Python中操作数据离不开Numpy。 Numpy的核心是ndarray对象,由Python的n维数组封装而来,但通过C语言预编译相关的数组操作,因此比原生Python具有更高的执行效率,但仍然使用Python语言编码,这样就同时具有简洁的代码和高效的运行速度。ndarry与数组有些区别值得注意,numpy数组中的元素都具有相同的类型,并且在创建时就确定了固定的大小,这与Python数组对象可以动态增长不同。 # coding:utf-8 import numpy as np 3,引入math库 math库是python提供的内置数学类函数库,math库不支持复数类型,仅支持整数和浮点数运算。math库一共提供了4个数字常数和44个函数。44个函数共分为4类,包括16个数值表示函数,8个幂对数函数,16个三角对数函数和4个高等特殊函数。 import math 4,引入collections库下的Counter Counter(计数器)是对字典的补充,用于追踪值的出现次数。 Counter是一个继承了字典的类(Counter(dict)) from collections import Counter 5,定义阻尼系数和最大迭代数 阻尼系数:其意义是,在任意时刻,用户到达某页面后并继续向后浏览的概率;该数值是根据上网者使用浏览器书签的平均频率估算而得 pr_config = {'alpha': 0.85, 'max_iter': 100} 6,定义滑动窗口的词语数 同时出现在滑动窗口里的词语,就认为他们直接存在共现关系 windows = 3 7,定义把词转换成矩阵的函数word_adj_matrix def word_adj_matrix(words_pro, windows, word_num, word_index): """ Adjacency Matrix :param windows: :return: """ def _word_combine(words, window): """ Keyword arguments: :param window: """ if window < 2: window = 2 for x in range(1, window): if x >= len(words): break words2 = words[x:] res = zip(words, words2) for r in res: yield r matrix = np.zeros((word_num, word_num)) for words in words_pro: for w1, w2 in _word_combine(words, windows): if w1 in word_index and w2 in word_index: index1 = word_index.get(w1) index2 = word_index.get(w2) matrix[index1][index2] = 1.0 matrix[index2][index1] = 1.0 return matrix 8,定义函数_build_adjacency_matrix 功能是返回邻接矩阵 def _build_adjacency_matrix(): adj_matrix = word_adj_matrix(words_pro,windows,word_num,word_index) return adj_matrix 9,定义函数words_info用于提取文本中的词信息 def words_info(words_list): """ :param words_list: :return: """ word_index = dict() index_word = dict() word_num = 0 #for index_s, words in enumerate(words_list): for index_s, words in enumerate(words_list): for index_w, word in enumerate(words): word_index[word] = word_num index_word[word_num] = word word_num += 1 return word_index, index_word, word_num 10,定义按分数高低排序的函数 def get_sorted_items(scores, index_items): """ :param scores: :param index_items: :return: list[tuple] """ items_scores = dict() for index, score in scores.items(): items_scores[index_items.get(index)] = score sorted_items = sorted(items_scores.items(), key=lambda item: item[1], reverse=True) return sorted_items 11,定义打分函数 def _score_items(): adj_matrix = _build_adjacency_matrix() scores = cal_score(adj_matrix, **pr_config) sorted_items = get_sorted_items(scores, index_word) return sorted_items def cal_score(ad_matrix, alpha=0.85, max_iter=100): N = len(ad_matrix) ad_sum = ad_matrix.sum(axis=0).astype(float) ad_sum[ad_sum == 0.0] = 0.001 ad_matrix = ad_matrix / ad_sum pr = np.full([N, 1], 1 / N) for _ in range(max_iter): pr = np.dot(ad_matrix, pr) * alpha + (1 - alpha) pr = pr / pr.sum() scores = dict(zip(range(len(pr)), [i[0] for i in pr])) return scores 12,测试运行textRank算法 针对前面已经赋值的文本数组: [['国家发改委','表示','目前','两轮','储备投放','基本','实现','预期','目标','社会','各界','普遍','反映','储备投放','体现','国家','确保','大宗','商品','市场','供应','价格','稳定','决心','信心','引导','价格','预期','缓解','部分','行业','企业','原材料','成本','压力','','持续','关注','大宗商品','价格','走势','情况','统筹','利用','国内','国外','两种','资源','综合','采取','多种','措施','加大','增产','增供','适时','储备投放','加强','进出口','调节','加大','市场','监管','力度','切实','大宗商品','保供','稳价','工作']] 按textRank算法提取关键词并输出显示前10个词语和权重值,代码如下: words_pro = [['国家发改委','表示','目前','两轮','储备投放','基本','实现','预期','目标','社会','各界','普遍','反映','储备投放','体现','国家','确保','大宗','商品','市场','供应','价格','稳定','决心','信心','引导','价格','预期','缓解','部分','行业','企业','原材料','成本','压力','','持续','关注','大宗商品','价格','走势','情况','统筹','利用','国内','国外','两种','资源','综合','采取','多种','措施','加大','增产','增供','适时','储备投放','加强','进出口','调节','加大','市场','监管','力度','切实','大宗商品','保供','稳价','工作']] word_index, index_word, word_num = words_info(words_pro) adj_matrix = _build_adjacency_matrix() scores = cal_score(adj_matrix, **pr_config) sorted_items = get_sorted_items(scores, index_word) sorted_words = _score_items() for i in range(10): print(sorted_words[i]) 输出结果如下: ('储备投放', 0.0395812227834387) ('价格', 0.03797205182449198) ('大宗商品', 0.027626848952020996) ('加大', 0.02647060664572129) ('预期', 0.026377194274224802) ('市场', 0.025970947188766934) ('目前', 0.01638074626173421) ('保供', 0.01614905873953002) ('两种', 0.015619984391531823) ('国外', 0.015602284512916412) 13,下载Jupyter Notebook 下载notebook源代码请进:使用Python做TextRank关键词提取 |