TextRank算法源自于PageRank算法。PageRank算法最初是作为互联网网页排序的方法,经过轻微地改动,可以被应用于文本摘要领域。

本文分为两部分,第一部分介绍TextRank做文本自动摘要的原理,第二部分介绍用TextRank做中文新闻摘要的案例。

一、基于TextRank的自动摘要原理

1、PageRank算法

首先看PageRank的相关概念。PageRank对于每个网页页面都给出一个正实数,表示网页的重要程度,PageRank值越高,表示网页越重要,在互联网搜索的排序中越可能被排在前面。假设整个互联网是一个有向图,节点是网页,每条边是转移概率。网页浏览者在每个页面上依照连接出去的超链接,以等概率跳转到下一个网页,并且在网页上持续不断地进行这样的随机跳转,这个过程形成了一阶马尔科夫链,比如下图,每个笑脸是一个网页,既有其他网页跳转到该网页,该网页也会跳转到其他网页。在不断地跳转之后,这个马尔科夫链会形成一个平稳分布,而PageRank就是这个平稳分布,每个网页的PageRank值就是平稳概率。

PageRank的核心公式是PageRank值的计算公式。这个公式来自于《统计学习方法》,和很多博客上的公式有点轻微的差别,那就是等号右边的平滑项不是(1-d),而是(1-d)/n。

加平滑项是因为有些网页没有跳出去的链接,那么转移到其他网页的概率将会是0,这样就无法保证存在马尔科夫链的平稳分布。于是,我们假设网页以等概率(1/n)跳转到任何网页,再按照阻尼系数d,对这个等概率(1/n)与存在链接的网页的转移概率进行线性组合,那么马尔科夫链一定存在平稳分布,一定可以得到网页的PageRank值。

所以PageRank的定义意味着网页浏览者按照以下方式在网上随机游走:以概率d按照存在的超链接随机跳转,以等概率从超链接跳转到下一个页面;或以概率(1-d)进行完全随机跳转,这时以等概率(1/n)跳转到任意网页。

PageRank的计算是一个迭代过程,先假设一个初始的PageRank分布,通过迭代,不断计算所有网页的PageRank值,直到收敛为止,也就是:

2、TextRank算法

在文本自动摘要的案例中,TextRank和PageRank的相似之处在于:

  • 用句子代替网页

  • 任意两个句子的相似性等价于网页转换概率

  • 相似性得分存储在一个方形矩阵中,类似于PageRank的矩阵M

不过公式有些小的差别,那就是用句子的相似度类比于网页转移概率,用归一化的句子相似度代替了PageRank中相等的转移概率,这意味着在TextRank中,所有节点的转移概率不会完全相等。

然后迭代过程就和PageRank一致了。

3、TextRank做单领域多文本的自动摘要

用TextRank做单领域多文本的自动摘要的过程如下:

  • 把所有文章整合成文本数据,并把文本分割成单个句子;
  • 用WordAVG的方法,将每个句子中所有单词的词向量合并为句子的向量表示;
  • 计算句子向量间的相似性并存放在矩阵中,作为转移概率矩阵M;
  • 然后将转移概率矩阵转换为以句子为节点、相似性得分为边的图结构,用于句子TextRank计算;
  • 对句子按照TextRank值进行排序,排名最靠前的n个句子作为摘要。

好的,那下面我们就用TextRank算法,以及按照上面的流程,做一个新闻自动摘要的小案例。

二、基于TextRank的中文新闻摘要

参考了一篇用TextRank做英文新闻摘要的文章。

  1. 1、文章:《手把手|基于TextRank算法的文本摘要(附Python代码)》 https://mp.weixin.qq.com/s/fGaEYvo3WYKdzA3r8l6O3g
  2.  
  3. 2github地址 https://github.com/prateekjoshi565/textrank_text_summarization

本文要处理的新闻一共3篇,都是关于证监会主席易会满同志新官上任的报道,新闻的大致内容是易会满同志怎么对中国资本市场的改革指点江山。

文档的原网页(看到百家号,不要鄙视我):

这个小实践的github:https://github.com/DengYangyong/textrank_summarization

好,那就开始。

1、整合文档,划分句子

首先把文档读入,放在列表中,可以看到,有些句子已经被划分出来了。

  1. ['信息量巨大!易会满首秀,直面科创板8大问题,对散户加速入场笑而不语……',
  2. '每日经济新闻',
  3. '02-2717:56',
  4. '每经编辑:郭鑫 王晓波',
  5. '图片来源:新华社记者 李鑫 摄',
  6. '易会满上任一个月,还没有在公开场合说过一句话。',
  7. '2月27日下午三点半开始,中国证监会主席易会满在北京国新办出席其首场新闻发布会,离发布会开始前两小时现场已经座无虚席,只等易主席来到现场。此外,副主席李超、副主席方星海,上海证券交易所理事长黄红元等也共同出席。',
    ...]

不过通过观察,我们可以发现存在两个问题:

一是以[。?!;]作为句子的分隔符,那么列表中的每个字符串元素中可能有多个句子;

二是每个字符串元素可能以[:,]结尾,也就是说可能是一个不完整的句子。

考虑到这只是一个小案例,所以就没花太多时间,仅仅处理一下第一个问题,把句子按照[。?!;]进行划分,如果字符串元素是不完整的句子,那也作为一句。

  1. import numpy as np
  2. import pandas as pd
  3. import re,os,jieba
  4. from itertools import chain
  5.  
  6. """第一步:把文档划分成句子"""
  7.  
  8. # 文档所在的文件夹
  9. c_root = os.getcwd()+os.sep+"cnews"+os.sep
  10.  
  11. sentences_list = []
  12. for file in os.listdir(c_root):
  13. fp = open(c_root+file,'r',encoding="utf8")
  14. for line in fp.readlines():
  15. if line.strip():
  16. # 把元素按照[。!;?]进行分隔,得到句子。
  17. line_split = re.split(r'[。!;?]',line.strip())
  18. # [。!;?]这些符号也会划分出来,把它们去掉。
  19. line_split = [line.strip() for line in line_split if line.strip() not in ['。','!','?',';'] and len(line.strip())>1]
  20. sentences_list.append(line_split)
  21. sentences_list = list(chain.from_iterable(sentences_list))
  22. print("前10个句子为:\n")
  23. print(sentences_list[:10])
  1. 10个句子为:
  2.  
  3. ['信息量巨大',
  4. '易会满首秀,直面科创板8大问题,对散户加速入场笑而不语……',
  5. '每日经济新闻',
  6. '02-2717:56',
    '每经编辑:郭鑫 王晓波',
  7. '图片来源:新华社记者 李鑫 摄',
  8. '易会满上任一个月,还没有在公开场合说过一句话',
  9. '2月27日下午三点半开始,中国证监会主席易会满在北京国新办出席其首场新闻发布会,离发布会开始前两小时现场已经座无虚席,只等易主席来到现场',
  10. '此外,副主席李超、副主席方星海,上海证券交易所理事长黄红元等也共同出席',
  11. '这可能是这个月国内关注的人最多的一场新闻发布会了']

2、文本预处理

文本预处理包括去除停用词和非汉字字符,并进行分词。处理的过程要保证处理之后的句子的数量和处理之前的一样,因为后面我们计算了每个句子的textrank值之后,需要根据textrank值的大小,取出相应的句子作为摘要。

比如 '02-2717:56' 这个句子整个被过滤了,那就令这个句子为[],下面也会给它一个句子的向量表示,只是元素都为0。

  1. """第二步:文本预处理,去除停用词和非汉字字符,并进行分词"""
  2.  
  3. #创建停用词列表
  4. stopwords = [line.strip() for line in open('./stopwords.txt',encoding='UTF-8').readlines()]
  5.  
  6. # 对句子进行分词
  7. def seg_depart(sentence):
  8. # 去掉非汉字字符
  9. sentence = re.sub(r'[^\u4e00-\u9fa5]+','',sentence)
  10. sentence_depart = jieba.cut(sentence.strip())
  11. word_list = []
  12. for word in sentence_depart:
  13. if word not in stopwords:
  14. word_list.append(word)
  15. # 如果句子整个被过滤掉了,如:'02-2717:56'被过滤,那就返回[],保持句子的数量不变
  16. return word_list
  17.  
  18. sentence_word_list = []
  19. for sentence in sentences_list:
  20. line_seg = seg_depart(sentence)
  21. sentence_word_list.append(line_seg)
  22. print("一共有",len(sentences_list),'个句子。\n')
  23. print("前10个句子分词后的结果为:\n",sentence_word_list[:10])
  24.  
  25. # 保证处理后句子的数量不变,我们后面才好根据textrank值取出未处理之前的句子作为摘要。
  26. if len(sentences_list) == len(sentence_word_list):
  27. print("\n数据预处理后句子的数量不变!")
  1. 一共有 347 个句子。
  2.  
  3. 10个句子分词后的结果为:
  4. [['信息量'],
    ['易会', '满首秀', '直面', '科创板', '散户', '加速', '入场', '笑', '不语'],
    ['每日', '经济', '新闻'],
    [],
    ['每经', '编辑', '郭鑫', '王晓波'],
    ['图片', '来源', '李鑫', '摄'],
    ['易会', '上任', '一个月', '公开场合', '说', '一句', '话'],
    ['三点', '中国证监会', '主席', '易会', '北京', '国新办', '出席', '首场', '新闻', '发布会', '发布会', '前', '两', '小时', '现场', '座无虚席', '易', '主席', '来到', '现场'],
    ['副', '主席', '李超', '副', '主席', '星海', '上海证券交易所', '理事长', '黄红元', '出席'],
    ['国内', '关注', '一场', '新闻', '发布会']]
  5.  
  6. 数据预处理后句子的数量不变!

3、加载word2vec词向量

从这里下载了金融新闻word2vec词向量:https://github.com/Embedding/Chinese-Word-Vectors。

词向量是300维的,字和词语都有。我们把词向量加载进来,做成一个字典,共有467140个词语或字。

  1. """第三步:准备词向量"""
  2.  
  3. word_embeddings = {}
  4. f = open('./sgns.financial.char', encoding='utf-8')
  5. for line in f:
  6. # 把第一行的内容去掉
  7. if '467389 300\n' not in line:
  8. values = line.split()
  9. # 第一个元素是词语
  10. word = values[0]
  11. embedding = np.asarray(values[1:], dtype='float32')
  12. word_embeddings[word] = embedding
  13. f.close()
  14. print("一共有"+str(len(word_embeddings))+"个词语/字。")
  1. 一共有467140个词语/字。

4、得到词语的embedding,用WordAVG作为句子的向量表示

WordAVG也就是先得到句子中的所有词语的词向量,然后求词向量的平均,作为该句子的向量表示。WordAVG可以用来计算句子的相似度。

  1. """第四步:得到词语的embedding,用WordAVG作为句子的向量表示"""
  2.  
  3. sentence_vectors = []
  4. for i in sentence_word_list:
  5. if len(i)!=0:
  6. # 如果句子中的词语不在字典中,那就把embedding设为300维元素为0的向量。
  7. # 得到句子中全部词的词向量后,求平均值,得到句子的向量表示
  8. v = sum([word_embeddings.get(w, np.zeros((300,))) for w in i])/(len(i))
  9. else:
  10. # 如果句子为[],那么就向量表示为300维元素为0个向量。
  11. v = np.zeros((300,))
  12. sentence_vectors.append(v)

5、计算句子之间的余弦相似度,构成相似度矩阵

  1. """第五步:计算句子之间的余弦相似度,构成相似度矩阵"""
  2. sim_mat = np.zeros([len(sentences_list), len(sentences_list)])
  3.  
  4. from sklearn.metrics.pairwise import cosine_similarity
  5.  
  6. for i in range(len(sentences_list)):
  7. for j in range(len(sentences_list)):
  8. if i != j:
  9. sim_mat[i][j] = cosine_similarity(sentence_vectors[i].reshape(1,300), sentence_vectors[j].reshape(1,300))[0,0]
  10. print("句子相似度矩阵的形状为:",sim_mat.shape)
  1. 句子相似度矩阵的形状为: (347, 347)

6、迭代得到句子的textrank值,排序并取出摘要

以句子为节点、相似性得分为转移概率,构建图结构,然后迭代得到句子的TextRank分数。

对句子按照TextRank值进行降序排序,取出排名最靠前的10个句子作为摘要。

  1. """第六步:迭代得到句子的textrank值,排序并取出摘要"""
  2. import networkx as nx
  3.  
  4. # 利用句子相似度矩阵构建图结构,句子为节点,句子相似度为转移概率
  5. nx_graph = nx.from_numpy_array(sim_mat)
  6.  
  7. # 得到所有句子的textrank值
  8. scores = nx.pagerank(nx_graph)
  9.  
  10. # 根据textrank值对未处理的句子进行排序
  11. ranked_sentences = sorted(((scores[i],s) for i,s in enumerate(sentences_list)), reverse=True)
  12.  
  13. # 取出得分最高的前10个句子作为摘要
  14. sn = 10
  15. for i in range(sn):
  16. print("第"+str(i+1)+"条摘要:\n\n",ranked_sentences[i][1],'\n')
  1. 1条摘要:
  2.  
  3. 在新闻发布会上,易会满表示,我到证监会工作今天是31天,刚刚满月,是资本市场的新兵,从市场参与者到监管者,角色转换角色挑战很大,如履薄冰,不敢懈怠,唯恐辜负中央信任和市场期待,这也是我做好工作的动力,
    近期加强调查研究,和部门协作维护市场平稳发展,维护科创板前期基础工作
  4.  
  5. 2条摘要:
  6.  
  7. 易会满在新闻发布会上表示,防止发生系统性风险是底线和根本任务,当前受国内外多种因素影响,资本市场风险形式严峻复杂,证监会将坚持精准施策,做好股票质押私募基金、场外配资和地方各类场所的重点领域风险的防范化解
    和处置工作,完善资本市场逆周期机制,健全及时反映风险波动系统,运用大数据、人工智能等手段对上市公司专业监管,平衡事前、事中、事后关系,监管端口前移,强化监管效能
  8.  
  9. 3条摘要:
  10.  
  11. 证监会将坚持精准施策,做好股票质押私募基金、场外配资和地方各类场所的重点领域风险的防范化解和处置工作,完善资本市场逆周期机制,健全及时反映风险波动系统,运用大数据、人工智能等手段对上市公司专业监管,
    平衡事前、事中、事后关系,监管端口前移,强化监管效能,切实做好打铁必须自身硬,做好中介机构和高管的强监管
  12.  
  13. 4条摘要:
  14.  
  15. 这两者出发点和规则不同,我来证监会后不断学习研究,这么专业的问题证监会有专业化的团队,资本市场是大的生态,什么叫市场,应该是依靠市场各参与者,调动市场参与者,市场规律办事, 培养健康生态比什么都重要,
    这一考验和要求比专业更重要,生态建设好了,资本市场的健康发展才有保证
  16.  
  17. 5条摘要:
  18.  
  19. 证监会副主席李超今天也给市场吃下定心丸:“对二级市场影响的问题,(科创板)设立时已经高度关注,在一系列的制度、规则层面作了相应安排
  20.  
  21. 6条摘要:
  22.  
  23. 他表示,第一,设立科创板主要目的是增强资本市场对实体经济的包容性,更好地服务具有核心技术、行业领先、有良好发展前景和口碑的企业,通过改革进一步完善支持创新的资本形成机制
  24.  
  25. 7条摘要:
  26.  
  27. 一是提高宏观思维能力,贴近市场各参与方,坚持市场导向、法治导向、监管导向,加强对资本市场宏观战略问题的研究思考,加强顶层设计,增强战略定力,稳步推进重点关注问题的改革创新,在改革中、在发展中破解难题
  28.  
  29. 8条摘要:
  30.  
  31. 集体学习的通稿中,中央给资本市场定的“法治化”要求有不少,比如“把好市场入口和市场出口两道关,加强全程监管”、“解决资本市场违法违规成本过低问题”
  32.  
  33. 9条摘要:
  34.  
  35. 易会满表示,证监会将以xijinping新时代中国特色社会主义思想为指导,在国务院金融委的统一指挥协调下,主动加强与相关部委、地方党委政府和市场各方的沟通协作,努力形成工作合力,共同促进资本市场高质量发展
  36.  
  37. 10条摘要:
  38.  
  39. 目前,资本市场已经回暖,这为改革提供了良好市场条件,我们要齐心协力,坚持“严标准、稳起步”的原则,积极做好落实和应对工作,注重各市场之间的平衡,确保改革平稳启动实施

Nice!

这样就完成了一个文本自动摘要的小实践了。

这是抽取型的摘要方法,以后再探索其他的文本自动摘要方法。

参考资料:

1、李航:《统计学习方法》(第二版)第21章

2、https://mp.weixin.qq.com/s/fGaEYvo3WYKdzA3r8l6O3g

文本自动摘要:基于TextRank的中文新闻摘要的更多相关文章

  1. 基于TextRank算法的文本摘要

    本文介绍TextRank算法及其在多篇单领域文本数据中抽取句子组成摘要中的应用. TextRank 算法是一种用于文本的基于图的排序算法,通过把文本分割成若干组成单元(句子),构建节点连接图,用句子之 ...

  2. AAAI 2018 论文 | 蚂蚁金服公开最新基于笔画的中文词向量算法

    AAAI 2018 论文 | 蚂蚁金服公开最新基于笔画的中文词向量算法 2018-01-18 16:13蚂蚁金服/雾霾/人工智能 导读:词向量算法是自然语言处理领域的基础算法,在序列标注.问答系统和机 ...

  3. 深度学习实战篇-基于RNN的中文分词探索

    深度学习实战篇-基于RNN的中文分词探索 近年来,深度学习在人工智能的多个领域取得了显著成绩.微软使用的152层深度神经网络在ImageNet的比赛上斩获多项第一,同时在图像识别中超过了人类的识别水平 ...

  4. [Python] 基于 jieba 的中文分词总结

    目录 模块安装 开源代码 基本用法 启用Paddle 词性标注 调整词典 智能识别新词 搜索引擎模式分词 使用自定义词典 关键词提取 停用词过滤 模块安装 pip install jieba jieb ...

  5. js控制文本框仅仅能输入中文、英文、数字与指定特殊符号

    JS 控制文本框仅仅能输入数字 <input onkeyup="value=value.replace(/[^0-9]/g,'')"onpaste="value=v ...

  6. 基于TextRank提取关键词、关键短语、摘要

    一.TextRank原理 TextRank是一种用来做关键词提取的算法,也可以用于提取短语和自动摘要.因为TextRank是基于PageRank的,所以首先简要介绍下PageRank算法. 1. Pa ...

  7. 自制基于HMM的中文分词器

    不像英文那样单词之间有空格作为天然的分界线, 中文词语之间没有明显界限.必须采用一些方法将中文语句划分为单词序列才能进一步处理, 这一划分步骤即是所谓的中文分词. 主流中文分词方法包括基于规则的分词, ...

  8. 基于CRF的中文分词

    http://biancheng.dnbcw.info/java/341268.html CRF简介 Conditional Random Field:条件随机场,一种机器学习技术(模型) CRF由J ...

  9. DL4NLP —— 序列标注:BiLSTM-CRF模型做基于字的中文命名实体识别

    三个月之前 NLP 课程结课,我们做的是命名实体识别的实验.在MSRA的简体中文NER语料(我是从这里下载的,非官方出品,可能不是SIGHAN 2006 Bakeoff-3评测所使用的原版语料)上训练 ...

随机推荐

  1. eclipse中 svn出现 E220000 解决办法

    这种情况,先试试修改svnserve.conf 中的 anon-access = none 然后重启eclipse   如果还是不行,还有可能是因为你修改了svn的配置链接后 跟他人的svn连接方式有 ...

  2. python cookbook第三版学习笔记九:函数

    接受任意数量参数的函数. 当传入函数的参数个数很多的时候,在函数定义的时候不需要为每一个参数定义一个变量,可以用*rest的方式来包含多余的参数. 如下面的代码,*rest包含了2,3,4这3个参数. ...

  3. SVN支干合并(转载)

    分支用来维护独立的开发支线,在一些阶段,你可能需要将分支上的修改合并到最新版本,或者将最新版本的修改合并到分支. 此操作十分重要,在团队开发中,如果你是SVN 的维护者此环节可以说是必不可少,因为团队 ...

  4. SAP 增强表MODSAP 和TFDIR

    2.第二代增强(基于函数模块的增强),用于SMOD和CMOD 维护 在SAP发布的版本中,使用Call customer-function 'xxx'调用函数模块的, 所以你可以通过在程序中搜索 cu ...

  5. ABAP-创建信息记录

    CALL FUNCTION 'ME_INITIALIZE_INFORECORD'. CALL FUNCTION 'ME_DIRECT_INPUT_INFORECORD' *&--------- ...

  6. 【AWS】亚马逊云常用服务解释

    新公司使用的是亚马逊服务,刚开始的时候,对很多名词不太明白,总结了一下如下 1,EC2 这个是亚马逊的一种服务器服务,可以理解为跟vmware差不多,EC2为虚拟机提供载体,EC2上跑虚拟机服务器. ...

  7. 【Leetcode-easy】Valid Parentheses

    思路:读取字符串中的每一个字符,并与栈顶元素进行比较,如果匹配则栈顶元素出栈,否则进栈.直到全部元素都出栈,否则该括号字符串不合法.需要注意细节. public boolean isValid(Str ...

  8. 【转】Java中的代码点与代码单元

    转载自:http://blog.csdn.net/xujinsmile/article/details/8526387 最近看core java,之前一直不明白,看了不少帖子和博客,总算搞明白了. J ...

  9. Sql 工资第二高(考虑并列)

    --题目:Employee表中有ID,Name,Salary三列,求薪资排序第二高的Employee的Name select * FROM [Employee] --等于2时为空,因为有并列第一 SE ...

  10. JDK中主要的包介绍