精华内容
下载资源
问答
  • TextRank

    千次阅读 2019-02-26 11:43:52
    TextRank与PageRank TextRank的灵感来源于大名鼎鼎的PageRank算法,这是一个用作网页重要度排序的算法。 这个算法是基于图的,每个网页可以看作是一个图中的结点,如果网页A能够跳转到网页B,那么则有一条A-&...

    TextRank与PageRank

    TextRank的灵感来源于大名鼎鼎的PageRank算法,这是一个用作网页重要度排序的算法。

    这个算法是基于图的,每个网页可以看作是一个图中的结点,如果网页A能够跳转到网页B,那么则有一条A->B的有向边。这样,我们就可以构造出一个有向图了。然后,利用公式:

    经过多次迭代就可以获得每个网页对应的权重。下面是公式每个元素的含义:

    可以发现,这个方法只要构造好图,对应关系自然就有了,这实际上是一个比较通用的算法。那么对于文本来说也是同样的,只要我们能够构造出一个图,图中的结点是单词/句子,只要我们通过某种方法定义这些结点存在某种关系,那么我们就可以使用上面的算法,得到一篇文章中的关键词/摘要。

    使用TextRank提取关键词

    提取关键词,可以采取和“网页中选哪个网页比较重要”类似的方法,只需要想办法把图构建出来。

    图的结点是“单词”。把文章拆成句子,每个句子再拆成单词,以单词为结点。

    那么边如何定义呢?这里就可以利用n-gram的思路,简单来说,某个单词,只与它附近的n个单词有关,即与它附近的n个词对应的结点连一条无向边(两个有向边)。

    另外,还可以做一些操作,比如把某类词性的词删掉,一些自定义词删掉,只保留一部分单词,只有这些词之间能够连边。
     

    使用TextRank提取文章摘要

    提取文章摘要以句子为结点。计算两个句子的相似度来定义边。似度的公式:

    简单来说就是,两个句子单词的交集除以两个句子的长度。然后还有一点就是,其他计算相似度的方法应该也是可行的,比如余弦相似度,最长公共子序列之类的,不过论文里一笔带过了。

     

    展开全文
  • textrank:Python 3的TextRank实现
  • TextRank, TextRank算法提取关键词的Java实现
  • textrank-js TextRank 是一种文本摘要算法,由 Rada Mihalcea 和 Paul Tarau 编写。 这里的代码基于他们的论文“TextRank:将秩序带入文本”。 我注意到有很多实现,但是这个实现是为了演示算法而没有任何额外的...
  • textrank:通过使用Textrank算法查找相关的句子和关键字来汇总文本
  • TextRank_Algorithm TextRank的简单实现 切分文章:把给定的文本使用标点或者空格切分成若干个句子; Text = [S1, S2, ... Sn] 保留关键词:对于每个句子,进行分词和词性标注处理,并过滤掉停用词,只保留指定词性...
  • 文本排名 使用 textrank 算法提取关键字
  • TextRank或自动汇总 自动汇总是使用计算机程序缩减文本文档以创建保留原始文档最重要要点的摘要的过程。 可以做出连贯摘要的技术会考虑变量,例如长度,写作风格和语法。 自动数据汇总是机器学习和数据挖掘的一部分...
  • TextRank算法的基本原理及textrank4zh使用实例

    万次阅读 多人点赞 2018-05-18 17:28:51
    TextRank算法是一种文本排序算法,由谷歌的网页重要性排序算法PageRank算法改进而来,它能够从一个给定的文本中提取出该文本的关键词、关键词组,并使用抽取式的自动文摘方法提取出该文本的关键句。其提出论文是: ...

        TextRank算法是一种文本排序算法,由谷歌的网页重要性排序算法PageRank算法改进而来,它能够从一个给定的文本中提取出该文本的关键词关键词组,并使用抽取式的自动文摘方法提取出该文本的关键句。其提出论文是: Mihalcea R, Tarau P. TextRank: Bringing order into texts[C]. Association for Computational Linguistics, 2004. 论文的百度学术下载地址为:点击打开链接本文将首先介绍TextRank算法的基本原理,然后给出Python中TextRank算法的中文文本实现模块textrank4zh的使用实例。

    1 TextRank算法的基本原理

        TextRank算法是由网页重要性排序算法PageRank算法迁移而来:PageRank算法根据万维网上页面之间的链接关系计算每个页面的重要性;TextRank算法将词视为“万维网上的节点”,根据词之间的共现关系计算每个词的重要性,并将PageRank中的有向边变为无向边。所以,在介绍TextRank算法之前,先介绍一下PageRank算法。

    1.1 PageRank算法的基本概念和原理

        PageRank算法的起源要从搜索引擎的发展讲起。早期的搜索引擎普遍采用分类目录方法,即通过人工对网页进行分类,整理出高质量的网站。随着网页的增多,人工分类的方法变得不现实,人们开始尝试使用文本检索的方法,即通过计算用户查询的关键词与网页内容的相关程度来返回搜索结果。这种方法突破了网页数量的限制,但是这种方法的效果并不总是很好,因为某些网站会刻意“操作”某些关键词从而使自己的搜索排名靠前。这一问题在1998年4月的第七届国际万维网大会上得以解决——Larry Page和Sergey Brin提出了PageRank算法。该算法通过计算网页链接的数量和质量来粗略估计网页的重要性,算法创立之初即应用在谷歌的搜索引擎中,对网页进行排名。

        PageRank算法的核心思想如下:

    • 如果一个网页被很多其他网页链接到,说明这个网页比较重要,即该网页的PR值(PageRank值)会相对较高;
    • 如果一个PR值很高的网页链接到一个其他网页,那么被链接到的网页的PR值会相应地因此而提高。

        以投票机制的观点来看,一个网页的得票数由所有链向它的网页的得票数经过递归算法来得到,有到一个网页的超链接相当于对该网页投了一票。

        为了便于理解,考虑以下情境:

              

    1)如上左图,假设一个只由4个网页组成的集合:A、B、C和D,如果网页B、C、D都链向网页A,且网页B、C、D均没有链出,那么网页A的PR值将是网页B、C、D的PR值之和:


    2)如上右图,继续假设在上述情境下,网页B有链接链向网页C,网页D有链接链向网页A、B、C,一个网页不能多次投票,所以网页B投给它链向的网页1/2票,网页D投给它链向的网页1/3票,计算此情境下网页A的PR值为:


    即,在一个网页为其他网页投票时,根据链出总数平分该网页的PR值,将其作为该网页为其链向网页所投票数,即:


    3)再抽象一下,建立一个简化模型,对于任意的网页i,它的PR值可以表示如下:


    :网页i的PR值

    :网页j的PR值

    :所有链接到网页i的网页集合

    :网页j的对外链出数

        以上讲的是PageRank算法的简单模型,但是简单模型并不适用于只链出自己的网页或几个网页的链出形成一个循环的情况,所以考虑更具普遍性的PageRank算法模型——随机浏览模型。

        随机浏览模型的假设是这样的:假定一个网页浏览者从一个随机页面开始浏览,浏览者不断点击当前网页的链接开始下一次浏览。但是,浏览者会逐渐厌倦并开始随机浏览网页。随机浏览的方式更符合用户的真实浏览行为,避免了上述情况的发生,由此产生了随机浏览模型,随机浏览模型中每个网页的PR值通过以下公式计算:


    网页i的PR值

    网页j的PR值

    网页j的对外链出数

    所有链接到网页i的网页集合

    :网络中网页的总数

    :阻尼系数,即按照超链接进行浏览的概率,一般取经验值为0.85

    :浏览者随机跳转到一个新网页的概率

        一个网页的PR值是由其他网页的PR值计算得到的。由于PR=A*PR(A为概率转移矩阵)满足马尔科夫链的性质,那么通过迭代可以得到所有网页的PR值。经过重复计算,这些网页的PR值会趋于正常和稳定。

        随着研究的深入,目前PageRank算法被广泛应用于众多方面,例如学术论文的重要性排名、学术论文作者的重要性排序、网络爬虫、关键词与关键句的抽取等。

    1.2 从PageRank算法到TextRank算法

        TextRank算法是由PageRank算法改进而来的,二者的思想有相同之处,区别在于:PageRank算法根据网页之间的链接关系构造网络,而TextRank算法根据词之间的共现关系构造网络;PageRank算法构造的网络中的边是有向无权边,而TextRank算法构造的网络中的边是无向有权边。TextRank算法的核心公式如下,其中用于表示两个节点之间的边连接具有不同的重要程度:


        为了便于理解,给出使用TextRank算法提取关键词关键词组的具体步骤如下:

    1)将给定的文本按照整句进行分割,即

    2)对于每个句子,对其进行分词和词性标注,然后剔除停用词,只保留指定词性的词,如名词、动词、形容词等,即,其中为句子i中保留下的词;

    3)构建词图,其中V为节点集合,由以上步骤生成的词组成,然后采用共现关系构造任意两个节点之间的边:两个节点之间存在边仅当它们对应的词在长度为K的窗口中共现,K表示窗口大小,即最多共现K个单词,一般K取2;

    4)根据上面的公式,迭代计算各节点的权重,直至收敛;

    5)对节点的权重进行倒序排序,从中得到最重要的t个单词,作为top-t关键词;

    6)对于得到的top-t关键词,在原始文本中进行标记,若它们之间形成了相邻词组,则作为关键词组提取出来。

        从给定文本中提取关键句时,将文本中的每个句子分别看作一个节点,如果两个句子有相似性,则认为这两个句子对应的节点之间存在一条无向有权边,衡量句子之间相似性的公式如下:


    :两个句子

    :句子中的词

        分子部分的意思是同时出现在两个句子中的同一个词的数量,分母是对句子中词的个数求对数后求和,这样设计可以遏制较长的句子在相似度计算上的优势。

        根据以上相似度计算公式循环计算任意两个节点之间的相似度,设置阈值去掉两个节点之间相似度较低的边连接,构建出节点连接图,然后迭代计算每个节点的TextRank值,排序后选出TextRank值最高的几个节点对应的句子作为关键句。

    1.3 textrank4zh模块源码解读

        textrank4zh模块是针对中文文本的TextRank算法的python算法实现,该模块的下载地址为:点击打开链接

        对其源码解读如下:

        util.py:textrank4zh模块的工具包,TextRank算法的核心思想在该文件中实现。

    # -*- encoding:utf-8 -*-
    """
    @author:   letian
    @homepage: http://www.letiantian.me
    @github:   https://github.com/someus/
    """
    from __future__ import (absolute_import, division, print_function,
    						unicode_literals)
    
    import os
    import math
    import networkx as nx
    import numpy as np
    import sys
    
    try:
    	reload(sys)
    	sys.setdefaultencoding('utf-8')
    except:
    	pass
    
    sentence_delimiters = ['?', '!', ';', '?', '!', '。', ';', '……', '…', '\n']
    allow_speech_tags = ['an', 'i', 'j', 'l', 'n', 'nr', 'nrfg', 'ns', 'nt', 'nz', 't', 'v', 'vd', 'vn', 'eng']
    
    PY2 = sys.version_info[0] == 2
    if not PY2:
    	# Python 3.x and up
    	text_type = str
    	string_types = (str,)
    	xrange = range
    
    
    	def as_text(v):  ## 生成unicode字符串
    		if v is None:
    			return None
    		elif isinstance(v, bytes):
    			return v.decode('utf-8', errors='ignore')
    		elif isinstance(v, str):
    			return v
    		else:
    			raise ValueError('Unknown type %r' % type(v))
    
    
    	def is_text(v):
    		return isinstance(v, text_type)
    
    else:
    	# Python 2.x
    	text_type = unicode
    	string_types = (str, unicode)
    	xrange = xrange
    
    
    	def as_text(v):
    		if v is None:
    			return None
    		elif isinstance(v, unicode):
    			return v
    		elif isinstance(v, str):
    			return v.decode('utf-8', errors='ignore')
    		else:
    			raise ValueError('Invalid type %r' % type(v))
    
    
    	def is_text(v):
    		return isinstance(v, text_type)
    
    __DEBUG = None
    
    
    def debug(*args):
    	global __DEBUG
    	if __DEBUG is None:
    		try:
    			if os.environ['DEBUG'] == '1':
    				__DEBUG = True
    			else:
    				__DEBUG = False
    		except:
    			__DEBUG = False
    	if __DEBUG:
    		print(' '.join([str(arg) for arg in args]))
    
    
    class AttrDict(dict):
    	"""Dict that can get attribute by dot"""
    
    	def __init__(self, *args, **kwargs):
    		super(AttrDict, self).__init__(*args, **kwargs)
    		self.__dict__ = self
    
    
    def combine(word_list, window=2):
    	"""构造在window下的单词组合,用来构造单词之间的边。
    
    	Keyword arguments:
    	word_list  --  list of str, 由单词组成的列表。
    	windows    --  int, 窗口大小。
    	"""
    	if window < 2: window = 2
    	for x in xrange(1, window):
    		if x >= len(word_list):
    			break
    		word_list2 = word_list[x:]
    		res = zip(word_list, word_list2)
    		for r in res:
    			yield r
    
    
    def get_similarity(word_list1, word_list2):
    	"""默认的用于计算两个句子相似度的函数。
    
    	Keyword arguments:
    	word_list1, word_list2  --  分别代表两个句子,都是由单词组成的列表
    	"""
    	words = list(set(word_list1 + word_list2))
    	vector1 = [float(word_list1.count(word)) for word in words]
    	vector2 = [float(word_list2.count(word)) for word in words]
    
    	vector3 = [vector1[x] * vector2[x] for x in xrange(len(vector1))]
    	vector4 = [1 for num in vector3 if num > 0.]
    	co_occur_num = sum(vector4)
    
    	if abs(co_occur_num) <= 1e-12:
    		return 0.
    
    	denominator = math.log(float(len(word_list1))) + math.log(float(len(word_list2)))  # 分母
    
    	if abs(denominator) < 1e-12:
    		return 0.
    
    	return co_occur_num / denominator
    
    
    def sort_words(vertex_source, edge_source, window=2, pagerank_config={'alpha': 0.85, }):
    	"""将单词按关键程度从大到小排序
    
    	Keyword arguments:
    	vertex_source   --  二维列表,子列表代表句子,子列表的元素是单词,这些单词用来构造pagerank中的节点
    	edge_source     --  二维列表,子列表代表句子,子列表的元素是单词,根据单词位置关系构造pagerank中的边
    	window          --  一个句子中相邻的window个单词,两两之间认为有边
    	pagerank_config --  pagerank的设置
    	"""
    	sorted_words = []
    	word_index = {}
    	index_word = {}
    	_vertex_source = vertex_source
    	_edge_source = edge_source
    	words_number = 0
    	for word_list in _vertex_source:
    		for word in word_list:
    			if not word in word_index:
    				word_index[word] = words_number
    				index_word[words_number] = word
    				words_number += 1
    
    	graph = np.zeros((words_number, words_number))
    
    	for word_list in _edge_source:
    		for w1, w2 in combine(word_list, window):
    			if w1 in word_index and w2 in word_index:
    				index1 = word_index[w1]
    				index2 = word_index[w2]
    				graph[index1][index2] = 1.0
    				graph[index2][index1] = 1.0
    
    	debug('graph:\n', graph)
    
    	nx_graph = nx.from_numpy_matrix(graph)
    	scores = nx.pagerank(nx_graph, **pagerank_config)  # this is a dict
    	sorted_scores = sorted(scores.items(), key=lambda item: item[1], reverse=True)
    	for index, score in sorted_scores:
    		item = AttrDict(word=index_word[index], weight=score)
    		sorted_words.append(item)
    
    	return sorted_words
    
    
    def sort_sentences(sentences, words, sim_func=get_similarity, pagerank_config={'alpha': 0.85, }):
    	"""将句子按照关键程度从大到小排序
    
    	Keyword arguments:
    	sentences         --  列表,元素是句子
    	words             --  二维列表,子列表和sentences中的句子对应,子列表由单词组成
    	sim_func          --  计算两个句子的相似性,参数是两个由单词组成的列表
    	pagerank_config   --  pagerank的设置
    	"""
    	sorted_sentences = []
    	_source = words
    	sentences_num = len(_source)
    	graph = np.zeros((sentences_num, sentences_num))
    
    	for x in xrange(sentences_num):
    		for y in xrange(x, sentences_num):
    			similarity = sim_func(_source[x], _source[y])
    			graph[x, y] = similarity
    			graph[y, x] = similarity
    
    	nx_graph = nx.from_numpy_matrix(graph)
    	scores = nx.pagerank(nx_graph, **pagerank_config)  # this is a dict
    	sorted_scores = sorted(scores.items(), key=lambda item: item[1], reverse=True)
    
    	for index, score in sorted_scores:
    		item = AttrDict(index=index, sentence=sentences[index], weight=score)
    		sorted_sentences.append(item)
    
    	return sorted_sentences
    
    
    if __name__ == '__main__':
    	pass

    Segmentation.py:包含用于分词和分句的类。

    # -*-coding:utf-8-*-
    
    # 把新版本的特性引入当前版本
    from __future__ import (absolute_import, division, print_function, unicode_literals)
    # 导入结巴分词的词性标注组件
    import jieba.posseg as pseg
    # 导入编码转换模块
    import codecs
    # 导入操作系统模块
    import os
    # 导入工具包组件
    from textrank4zh import util
    
    
    # 获取停用词文件的路径
    def get_default_stop_words_file():
    	# 获取当前脚本所在的路径
    	d = os.path.dirname(os.path.realpath(__file__))
    	# 返回停用词表所在路径,os.path.join方法用于将多个路径组合后返回
    	return os.path.join(d, 'stopwords.txt')
    
    
    """分词类"""
    
    
    class WordSegmentation(object):
    
    	"""初始化函数,获取词性列表和停用词表"""
    	def __init__(self, stop_words_file=None, allow_speech_tags=util.allow_speech_tags):
    		"""
    		:param stop_words_file:保存停用词表的文件路径,使用utf-8编码方式,每行存放一个停用词,若不是str类型,则使用默认的停用词
    		:param allow_speech_tags:默认的词性列表,用于过滤某些词性的词
    		:return:无
    		"""
    		# 词性列表
    		allow_speech_tags = [util.as_text(item) for item in allow_speech_tags]
    		# 将词性列表设置为默认的词性列表
    		self.default_speech_tags_filter = allow_speech_tags
    
    		# 使用set方法创建空集合
    		self.stop_words = set()
    		# 获取停用词文件的路径
    		self.stop_words_file = get_default_stop_words_file()
    		# 若停用词文件路径不是str类型,则使用默认的停用词
    		if type(stop_words_file is str):
    			self.stop_words_file = stop_words_file
    		# 打开并读取停用词文件,将其中的停用词加入停用词集合
    		for word in codecs.open(self.stop_words_file, 'r', 'utf-8', 'ignore'):
    			self.stop_words.add(word.strip())
    
    	"""对文本进行分词,返回的分词结果以列表方式存储"""
    	def segment(self, text, lower=True, user_stop_words=True, use_speech_tags_filter=False):
    		"""
    		:param text: 要进行分词的文本
    		:param lower: 是否要将单词小写,针对英文
    		:param user_stop_words: 若为True,表示使用停用词集合进行过滤,去掉停用词
    		:param use_speech_tags_filter:是否基于词性进行过滤,若为True,则使用默认的词性列表进行过滤
    		:return:词性过滤后的词列表
    		"""
    		# 待分词的文本
    		text = util.as_text(text)
    		# 词性标注结果列表
    		jieba_result = pseg.cut(text)
    
    		if use_speech_tags_filter == True:
    			# 进行词性过滤后的词性标注结果
    			jieba_result = [w for w in jieba_result if w.flag in self.default_speech_tags_filter]
    		else:
    			# 不进行词性过滤的词性标注结果
    			jieba_result = [w for w in jieba_result]
    
    		# 去除特殊符号
    
    		# 去除非语素字和词两端的空格
    		# 非语素字只是一个符号,字母x通常用于代表未知数、符号
    		word_list = [w.word.strip() for w in jieba_result if w.flag != 'x']
    		# 去除空字符
    		word_list = [word for word in word_list if len(word) > 0]
    
    		# 是否将英文单词小写
    		if lower:
    			word_list = [word.lower() for word in word_list]
    
    		# 是否使用停用词集合进行过滤
    		if user_stop_words:
    			word_list = [word.strip() for word in word_list if word.strip() not in self.stop_words]
    
    		# 返回词性过滤后的词列表
    		return word_list
    
    	"""将列表sentences中的每个元素/句子转换为由单词构成的列表"""
    	def segment_sentences(self, sentences, lower=True, user_stop_words=True, user_speech_tags_filter=False):
    		"""
    		:param sentences: 句子列表
    		:return: 以词性过滤后的词列表为元素的列表
    		"""
    		res = []
    		for sentence in sentences:
    			# 调用segment方法,将词性过滤后的词列表加入到列表中
    			res.append(self.segment(text=sentences, lower=lower, user_stop_words=user_stop_words, use_speech_tags_filter=user_speech_tags_filter))
    		# 返回以词性过滤后的词列表为元素的列表
    		return res
    
    
    """分句类"""
    
    
    class SentenceSegmentation(object):
    
    	"""初始化函数,获取用于分句的分隔符集合"""
    	def __init__(self, delimiters=util.sentence_delimiters):
    		"""
    		:param delimiters: 可迭代对象,用于拆分句子
    		"""
    		self.delimiters = set([util.as_text(item) for item in delimiters])
    
    	"""将文本划分为句子,返回句子列表"""
    	def segment(self, text):
    		# 获取文本
    		res = [util.as_text(text)]
    		# 调试
    		util.debug(res)
    		util.debug(self.delimiters)
    
    		# 分句,使用了两层循环
    		# 遍历分隔符对象
    		for sep in self.delimiters:
    			# res表示分句结果
    			text, res = res, []
    			# 遍历文本对象
    			for seq in text:
    				# 分句操作
    				res += seq.split(sep)
    		# 去除句子两端空格,并滤除空句
    		res = [s.strip() for s in res if len(s.strip() > 0)]
    		# 返回句子列表
    		return res
    
    
    """分割类"""
    
    
    class Segmentation(object):
    
    	"""初始化函数"""
    	def __init__(self, stop_word_file=None, allow_speech_tags=util.allow_speech_tags, delimiters=util.sentence_delimiters):
    		"""
    		:param stop_word_file: 停用词文件
    		:param allow_speech_tags: 词性列表,用于过滤某些词性的词
    		:param delimiters: 用于拆分句子的分隔符
    		"""
    		# 创建分词类的实例
    		self.ws = WordSegmentation(stop_word_file=stop_word_file, allow_speech_tags=allow_speech_tags)
    		# 创建分句类的实例
    		self.ss = SentenceSegmentation(delimiters=delimiters)
    
    	def segment(self, text, lower=False):
    		# 获取文本
    		text = util.as_text(text)
    		# 拆分文本,得到句子列表
    		sentences = self.ss.segment(text)
    		# 未进行词性过滤后的词列表
    		words_no_filter = self.ws.segment_sentences(sentences=sentences, lower=lower, user_stop_words=False, user_speech_tags_filter=False)
    		# 去掉停用词后的词列表
    		words_no_stop_words = self.ws.segment_sentences(sentences=sentences, lower=lower, user_stop_words=True, user_speech_tags_filter=False)
    		# 进行词性过滤并去掉停用词后的词列表
    		words_all_filters = self.ws.segment_sentences(sentences=sentences, lower=lower, user_stop_words=True, user_speech_tags_filter=True)
    		# 返回以上结果
    		return util.AttrDict(sentences=sentences, words_no_filter=words_no_filter, words_no_stop_words=words_no_stop_words, words_all_filters=words_all_filters)
    
    
    # 主模块
    if __name__ == '__main__':
    	# 空语句,保持程序结构的完整性
    	pass
    

    TextRank4Keyword.py:包含用于提取关键词和关键词组的类。

    #-*-coding:utf-8-*-
    
    # 把新版本的特性引入当前版本
    from __future__ import (absolute_import, division, print_function, unicode_literals)
    # 导入操作复杂网络的模块
    import networkx as nx
    # 导入数值计算模块
    import numpy as np
    # 导入工具包组件
    from textrank4zh import util
    # 导入Segmentation文件
    from textrank4zh.Segmentation import Segmentation
    
    
    class TextRank4Keyword(object):
    
    	"""初始化函数"""
    	def __init__(self, stop_words_file=None, allow_speech_tags=util.allow_speech_tags, delimiters=util.sentence_delimiters):
    		"""
    		:param stop_words_file:str类型,指定停用词文件的路径,若为其他类型,则使用默认的停用词文件
    		:param allow_speech_tags:词性列表,用于过滤某些词性的词
    		:param delimiters:用于拆分句子的分隔符,默认值为`?!;?!。;…\n`
    		"""
    		self.text = ''
    		self.Keywords = None
    		# 创建分割类的实例
    		self.seg = Segmentation(stop_words_file=stop_words_file, allow_speech_tags=allow_speech_tags, delimiters=delimiters)
    		# 句子列表
    		self.sentences = None
    		# 对sentences中每个句子分词而得到的两维列表
    		self.words_no_filter = None
    		# 去掉words_no_filter中的停止词而得到的两维列表
    		self.word_no_stop_words = None
    		# 保留words_no_stop_words中指定词性的单词而得到的两维列表
    		self.words_all_filters = None
    
    	"""分析文本的函数,体现算法思想的部分"""
    	def analyze(self, text, window=2, lower=False, vertex_source='all_filters', edge_source='no_stop_words', pagerank_config={'alpha': 0.85,}):
    		"""
    		:param text: 文本内容
    		:param window: 窗口大小,整型,用于构造单词之间的边,去默认值为2
    		:param lower: 是否将英文文本转换为小写,默认值为False
    		:param vertex_source: 选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来构造pagerank对应的图中的节点。默认值为`'all_filters'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'`。关键词也来自`vertex_source`
    		:param edge_source:选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来构造pagerank对应的图中的节点之间的边。默认值为`'no_stop_words'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'`。边的构造要结合`window`参数。
    		:param pagerank_config:pagerank算法参数配置,阻尼系数为0.85
    		"""
    		self.text = text
    		self.word_index = {}
    		self.index_word = {}
    		# 关键词列表
    		self.keywords = []
    		self.graph = None
    
    		result = self.seg.segment(text=text, lower=lower)
    		self.sentences = result.sentences
    		self.words_no_filter = result.words_no_filter
    		self.word_no_stop_words = result.word_no_stop_words
    		self.words_all_filters = result.words_all_filters
    
    		# 调试
    		util.debug(20 * '*')
    		util.debug('self.sentences in TextRank4Keyword:\n', ' || '.join(self.sentences))
    		util.debug('self.words_no_filter in TextRank4Keyword:\n', self.words_no_filter)
    		util.debug('self.words_no_stop_words in TextRank4Keyword:\n', self.words_no_stop_words)
    		util.debug('self.words_all_filters in TextRank4Keyword:\n', self.words_all_filters)
    
    		# 选项,几种模式
    		options = ['no_filter', 'no_stop_words', 'all_filters']
    		# 模式选择
    		if vertex_source in options:
    			_vertex_source = result['words_' +vertex_source]
    		else:
    			_vertex_source = result['words_all_filters']
    		if edge_source in options:
    			_edge_source = result['words_' + edge_source]
    		else:
    			_edge_source = result['words_no_stop_words']
    
    		self.keywords = util.sort_words(_vertex_source, _edge_source, window=window, pagerank_config=pagerank_config)
    
    
    	"""获取最重要的num个长度大于等于word_min_len的关键词"""
    	def get_keywords(self, num=6, word_min_len=1):
    		"""
    		:param num: 返回的关键词个数
    		:param word_min_len: 最小关键词长度
    		:return: 关键词列表
    		"""
    		result = []
    		count = 0
    		for item in self.keywords:
    			if count >= num:
    				break
    			if len(item.word) >= word_min_len:
    				result.append(item)
    				count += 1
    		return result
    
    	"""获取 keywords_num 个关键词构造的可能出现的短语,要求这个短语在原文本中至少出现的次数为min_occur_num"""
    	def get_keyphrases(self, keywords_num=12, min_occur_num=2):
    		"""
    		:param keywords_num: 返回的关键词短语个数
    		:param min_occur_num: 短语在文本中的最小出现次数
    		:return: 关键词短语列表
    		"""
    		# 关键词集合
    		keywords_set = set([item.word for item in self.get_keywords(num=keywords_num, word_min_len=1)])
    		# 关键词短语集合
    		keyphrases = set()
    		for sentence in self.words_no_filter:
    			one = []
    			for word in sentence:
    				if word in keywords_set:
    					one.append(word)
    				else:
    					if len(one) > 1:
    						# 将关键词组成关键词短语
    						keyphrases.add(''.join(one))
    					if len(one) == 0:
    						continue
    					else:
    						one = []
    			# 兜底
    			if len(one) > 1:
    				keyphrases.add(''.join(one))
    		# 在原文本中至少出现min_occur_num词
    		return [phrase for phrase in keyphrases if self.text.count(phrase) >= min_occur_num]
    
    # 主模块
    if __name__ == '__main__':
    	# 空语句,保持程序结构的完整性
    	pass
    

    TextRank4Sentence.py:包含用于提取关键句的类。

    # -*- encoding:utf-8 -*-
    """
    @author:   letian
    @homepage: http://www.letiantian.me
    @github:   https://github.com/someus/
    """
    from __future__ import (absolute_import, division, print_function,
    						unicode_literals)
    
    import networkx as nx
    import numpy as np
    
    from . import util
    from .Segmentation import Segmentation
    
    
    class TextRank4Sentence(object):
    
    	def __init__(self, stop_words_file=None,
    				 allow_speech_tags=util.allow_speech_tags,
    				 delimiters=util.sentence_delimiters):
    		"""
    		Keyword arguments:
    		stop_words_file  --  str,停止词文件路径,若不是str则是使用默认停止词文件
    		delimiters       --  默认值是`?!;?!。;…\n`,用来将文本拆分为句子。
    
    		Object Var:
    		self.sentences               --  由句子组成的列表。
    		self.words_no_filter         --  对sentences中每个句子分词而得到的两级列表。
    		self.words_no_stop_words     --  去掉words_no_filter中的停止词而得到的两级列表。
    		self.words_all_filters       --  保留words_no_stop_words中指定词性的单词而得到的两级列表。
    		"""
    		self.seg = Segmentation(stop_words_file=stop_words_file,
    								allow_speech_tags=allow_speech_tags,
    								delimiters=delimiters)
    
    		self.sentences = None
    		self.words_no_filter = None  # 2维列表
    		self.words_no_stop_words = None
    		self.words_all_filters = None
    
    		self.key_sentences = None
    
    	def analyze(self, text, lower=False,
    				source='no_stop_words',
    				sim_func=util.get_similarity,
    				pagerank_config={'alpha': 0.85, }):
    		"""
    		Keyword arguments:
    		text                 --  文本内容,字符串。
    		lower                --  是否将文本转换为小写。默认为False。
    		source               --  选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来生成句子之间的相似度。
    								 默认值为`'all_filters'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'`。
    		sim_func             --  指定计算句子相似度的函数。
    		"""
    
    		self.key_sentences = []
    
    		result = self.seg.segment(text=text, lower=lower)
    		self.sentences = result.sentences
    		self.words_no_filter = result.words_no_filter
    		self.words_no_stop_words = result.words_no_stop_words
    		self.words_all_filters = result.words_all_filters
    
    		options = ['no_filter', 'no_stop_words', 'all_filters']
    		if source in options:
    			_source = result['words_' + source]
    		else:
    			_source = result['words_no_stop_words']
    
    		self.key_sentences = util.sort_sentences(sentences=self.sentences,
    												 words=_source,
    												 sim_func=sim_func,
    												 pagerank_config=pagerank_config)
    
    	def get_key_sentences(self, num=6, sentence_min_len=6):
    		"""获取最重要的num个长度大于等于sentence_min_len的句子用来生成摘要。
    
    		Return:
    		多个句子组成的列表。
    		"""
    		result = []
    		count = 0
    		for item in self.key_sentences:
    			if count >= num:
    				break
    			if len(item['sentence']) >= sentence_min_len:
    				result.append(item)
    				count += 1
    		return result
    
    
    if __name__ == '__main__':
    	pass
    2 textrank4zh模块的使用

    2.1 textrank4zh模块的安装

        这里介绍几种安装Python模块的方法,仅供参考。

        1)python setup.py install --user
        2)sudo python setup.py install
        3)pip install textrank4zh --user
        4)sudo pip install textrank4zh

        textrank4zh模块在python2或python3中均可使用,它所依赖的其他模块要求满足:

        jieba >= 0.35; numpy >= 1.7.1;networkx >= 1.9.1

    2.2 textrank4zh的使用实例

        因为操作比较简单,所有直接以代码的形式展示例子,代码在python3环境下亲测可用。

    1)提取关键词、关键短语和关键句

    #-*-coding:utf-8-*-
    """
    @author:taoshouzheng
    @time:2018/5/18 8:20
    @email:tsz1216@sina.com
    """
    # 导入系统模块
    import sys
    # imp模块提供了一个可以实现import语句的接口
    from imp import reload
    
    # 异常处理
    try:
    	# reload方法用于对已经加载的模块进行重新加载,一般用于原模块有变化的情况
    	reload(sys)
    	# 设置系统的默认编码方式,仅本次有效,因为setdefaultencoding函数在被系统调用后即被删除
    	sys.setdefaultencoding('utf-8')
    except:
    	pass
    
    """
    展示textrank4zh模块的主要功能:
    提取关键词
    提取关键短语(关键词组)
    提取摘要(关键句)
    """
    
    # 导入编码转换模块
    import codecs
    # 从textrank4zh模块中导入提取关键词和生成摘要的类
    from textrank4zh import TextRank4Keyword, TextRank4Sentence
    
    # 待读取的文本文件,一则新闻
    file = r'C:\Users\Tao Shouzheng\Desktop\01.txt'
    # 打开并读取文本文件
    text = codecs.open(file, 'r', 'utf-8').read()
    
    # 创建分词类的实例
    tr4w = TextRank4Keyword()
    # 对文本进行分析,设定窗口大小为2,并将英文单词小写
    tr4w.analyze(text=text, lower=True, window=2)
    
    """输出"""
    print('关键词为:')
    # 从关键词列表中获取前20个关键词
    for item in tr4w.get_keywords(num=20, word_min_len=1):
    	# 打印每个关键词的内容及关键词的权重
    	print(item.word, item.weight)
    print('\n')
    
    print('关键短语为:')
    # 从关键短语列表中获取关键短语
    for phrase in tr4w.get_keyphrases(keywords_num=20, min_occur_num=2):
    	print(phrase)
    print('\n')
    
    # 创建分句类的实例
    tr4s = TextRank4Sentence()
    # 英文单词小写,进行词性过滤并剔除停用词
    tr4s.analyze(text=text, lower=True, source='all_filters')
    
    print('摘要为:')
    # 抽取3条句子作为摘要
    for item in tr4s.get_key_sentences(num=3):
    	# 打印句子的索引、权重和内容
    	print(item.index, item.weight, item.sentence)

    结果如下:

    关键词为:
    媒体 0.02155864734852778
    高圆圆 0.020220281898126486
    微 0.01671909730824073
    宾客 0.014328439104001788
    赵又廷 0.014035488254875914
    答谢 0.013759845912857732
    谢娜 0.013361244496632448
    现身 0.012724133346018603
    记者 0.01227742092899235
    新人 0.01183128428494362
    北京 0.011686712993089671
    博 0.011447168887452668
    展示 0.010889176260920504
    捧场 0.010507502237123278
    礼物 0.010447275379792245
    张杰 0.009558332870902892
    当晚 0.009137982757893915
    戴 0.008915271161035208
    酒店 0.00883521621207796
    外套 0.008822082954131174
    
    
    关键短语为:
    微博
    
    
    摘要为:
    0 0.07097195571711616 中新网北京12月1日电(记者 张曦) 30日晚,高圆圆和赵又廷在京举行答谢宴,诸多明星现身捧场,其中包括张杰(微博)、谢娜(微博)夫妇、何炅(微博)、蔡康永(微博)、徐克、张凯丽、黄轩(微博)等
    6 0.05410372364148859 高圆圆身穿粉色外套,看到大批记者在场露出娇羞神色,赵又廷则戴着鸭舌帽,十分淡定,两人快步走进电梯,未接受媒体采访
    27 0.04904283129838876 记者了解到,出席高圆圆、赵又廷答谢宴的宾客近百人,其中不少都是女方的高中同学

    2)展示textrank4zh模块的三种分词模式的效果

        三种分词模式分别为:

        words_no_filter模式:简单分词,不剔除停用词,不进行词性过滤

        words_no_stop_words模式:剔除停用词

        words_all_filters模式(默认):即剔除停用词,又进行词性过滤

    #-*-coding:utf-8-*-
    """
    @author:taoshouzheng
    @time:2018/5/18 14:52
    @email:tsz1216@sina.com
    """
    
    import codecs
    from imp import reload
    
    from textrank4zh import TextRank4Keyword, TextRank4Sentence
    
    import sys
    try:
    	reload(sys)
    	sys.setdefaultencoding('utf-8')
    except:
    	pass
    
    """测试3类分词的效果"""
    
    text = '这间酒店位于北京东三环,里面摆放很多雕塑,文艺气息十足。答谢宴于晚上8点开始。'
    tr4w = TextRank4Keyword()
    
    tr4w.analyze(text=text, lower=True, window=2)
    # 将文本划分为句子列表
    print('sentences:')
    for s in tr4w.sentences:
    	print(s)
    print('\n')
    
    # 对句子列表中的句子进行分词,不进行词性过滤
    print('words_no_filter:')
    # words为词列表,tr4w.words_no_filter为由词列表组成的列表
    for words in tr4w.words_no_filter:
    	print('/'.join(words))
    print('\n')
    
    # 打印去掉停用词的词列表
    print('words_no_stop_words:')
    for words in tr4w.words_no_stop_words:
    	print('/'.join(words))
    print('\n')
    
    # 打印去掉停用词并进行词性过滤之后的词列表
    print('words_all_filters:')
    for words in tr4w.words_all_filters:
    	print('/'.join(words))
    

    结果如下:

    sentences:
    这间酒店位于北京东三环,里面摆放很多雕塑,文艺气息十足
    答谢宴于晚上8点开始
    
    
    words_no_filter:
    这/间/酒店/位于/北京/东三环/里面/摆放/很多/雕塑/文艺/气息/十足
    答谢/宴于/晚上/8/点/开始
    
    
    words_no_stop_words:
    间/酒店/位于/北京/东三环/里面/摆放/很多/雕塑/文艺/气息/十足
    答谢/宴于/晚上/8/点
    
    
    words_all_filters:
    酒店/位于/北京/东三环/摆放/雕塑/文艺/气息
    答谢/宴于/晚上

    在本文的写作过程中,参考了一些文章或帖子,附上链接如下:

    1)python中jieba分词快速入门:点击打开链接

    2)jieba(结巴)分词种词性简介:点击打开链接

    3)TextRank算法:点击打开链接

    4)PageRank算法 到 textRank:点击打开链接

    5)PageRank排序算法详细介绍:点击打开链接

    6)PageRank:点击打开链接

    7)PageRank算法--从原理到实现:点击打开链接

    8)Textrank算法介绍:点击打开链接

    9)关键词提取算法-TextRank:点击打开链接

    10)最全中文停用词表整理(1893个):点击打开链接

    11)中文文本提取关键词、关键词组、关键句(textrank4zh使用)--python学习:点击打开链接

    12)谷歌背后的数学:点击打开链接

    不足之处,敬请指正!

    展开全文
  • TextRank示范 一个简单的网站,演示TextRank的提取摘要功能。 目前支持英语和中文。 主要更新 2021年3月 我部署了此演示的一个版本,在删除了USE和LASER。 现在,您无需在本地构建Docker映像即可尝试此演示。 该...
  • word2vec加textrank抽取文章摘要 使用word2vec计算句子间的相似度,然后使用PageRank计算句子分数,抽取前n个句子作为文本摘要。
  • TextRank算法介绍及实现

    万次阅读 多人点赞 2019-07-22 21:57:51
    目录 1、PageRank算法 2、TextRank算法 (1)关键词抽取(keyword extraction) (2)关键短语抽取(keyphrase extration...(1)基于Textrank4zh的TextRank算法实现 (2)基于jieba的TextRank算法实现 (3)...

    目录

    1、PageRank算法

    2、TextRank算法

    (1)关键词抽取(keyword extraction)

    (2)关键短语抽取(keyphrase extration)

    (3)关键句抽取(sentence extraction)

    3、TextRank算法实现

    (1)基于Textrank4zh的TextRank算法实现

    (2)基于jieba的TextRank算法实现

    (3)基于SnowNLP的TextRank算法实现

    4、PageRank算法与TextRank算法的区别


    1、PageRank算法

    PageRank算法通过计算网页链接的数量和质量来粗略估计网页的重要性,算法创立之初即应用在谷歌的搜索引擎中,对网页进行排名。 

    PageRank算法的核心思想如下:

    (1)链接数量:如果一个网页被越多的其他网页链接,说明这个网页越重要,即该网页的PR值(PageRank值)会相对较高;

    (2)链接质量:如果一个网页被一个越高权值的网页链接,也能表明这个网页越重要,即一个PR值很高的网页链接到一个其他网页,那么被链接到的网页的PR值会相应地因此而提高。

    PageRank算法计算公式

    PageRank算法论文The PageRank Citation Ranking: Bringing Order to the Web

    2、TextRank算法

    TextRank算法是一种基于图的用于关键词抽取和文档摘要的排序算法,由谷歌的网页重要性排序算法PageRank算法改进而来,它利用一篇文档内部的词语间的共现信息(语义)便可以抽取关键词,它能够从一个给定的文本中抽取出该文本的关键词、关键词组,并使用抽取式的自动文摘方法抽取出该文本的关键句。

    TextRank算法的基本思想是将文档看作一个词的网络,该网络中的链接表示词与词之间的语义关系。

    TextRank算法计算公式

    TextRank算法论文TextRank: Bringing Order into Texts

    TextRank算法主要包括:关键词抽取、关键短语抽取、关键句抽取。

    (1)关键词抽取(keyword extraction)

    关键词抽取是指从文本中确定一些能够描述文档含义的术语的过程。对关键词抽取而言,用于构建顶点集的文本单元可以是句子中的一个或多个字;根据这些字之间的关系(比如:在一个框中同时出现)构建边。根据任务的需要,可以使用语法过滤器(syntactic filters)对顶点集进行优化。语法过滤器的主要作用是将某一类或者某几类词性的字过滤出来作为顶点集。

    (2)关键短语抽取(keyphrase extration)

    关键词抽取结束后,我们可以得到的N个关键词,在原始文本中相邻的关键词构成关键短语。因此,从get_keyphrases函数的源码中我们可以看到,它先调用get_keywords抽取关键词,然后分析关键词是否存在相邻的情况,最后确定哪些是关键短语。

    (3)关键句抽取(sentence extraction)

    句子抽取任务主要针对的是自动摘要这个场景,将每一个sentence作为一个顶点,根据两个句子之间的内容重复程度来计算他们之间的“相似度”,以这个相似度作为联系,由于不同句子之间相似度大小不一致,在这个场景下构建的是以相似度大小作为edge权重的有权图。

    3、TextRank算法实现

    (1)基于Textrank4zh的TextRank算法实现

    # coding=utf-8
    from textrank4zh import TextRank4Keyword, TextRank4Sentence
    import jieba.analyse
    from snownlp import SnowNLP
    import pandas as pd
    import numpy as np
    
    #关键词抽取
    def keywords_extraction(text):
        tr4w = TextRank4Keyword(allow_speech_tags=['n', 'nr', 'nrfg', 'ns', 'nt', 'nz'])
        # allow_speech_tags   --词性列表,用于过滤某些词性的词
        tr4w.analyze(text=text, window=2, lower=True, vertex_source='all_filters', edge_source='no_stop_words',
                     pagerank_config={'alpha': 0.85, })
        # text    --  文本内容,字符串
        # window  --  窗口大小,int,用来构造单词之间的边。默认值为2
        # lower   --  是否将英文文本转换为小写,默认值为False
        # vertex_source  -- 选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来构造pagerank对应的图中的节点
        #                -- 默认值为`'all_filters'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'
        # edge_source  -- 选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来构造pagerank对应的图中的节点之间的边
        #              -- 默认值为`'no_stop_words'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'`。边的构造要结合`window`参数
    
        # pagerank_config  -- pagerank算法参数配置,阻尼系数为0.85
        keywords = tr4w.get_keywords(num=6, word_min_len=2)
        # num           --  返回关键词数量
        # word_min_len  --  词的最小长度,默认值为1
        return keywords
    
    #关键短语抽取
    def keyphrases_extraction(text):
        tr4w = TextRank4Keyword()
        tr4w.analyze(text=text, window=2, lower=True, vertex_source='all_filters', edge_source='no_stop_words',
                     pagerank_config={'alpha': 0.85, })
        keyphrases = tr4w.get_keyphrases(keywords_num=6, min_occur_num=1)
        # keywords_num    --  抽取的关键词数量
        # min_occur_num   --  关键短语在文中的最少出现次数
        return keyphrases
    
    #关键句抽取
    def keysentences_extraction(text):
        tr4s = TextRank4Sentence()
        tr4s.analyze(text, lower=True, source='all_filters')
        # text    -- 文本内容,字符串
        # lower   -- 是否将英文文本转换为小写,默认值为False
        # source  -- 选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来生成句子之间的相似度。
        # 		  -- 默认值为`'all_filters'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'
        # sim_func -- 指定计算句子相似度的函数
    
        # 获取最重要的num个长度大于等于sentence_min_len的句子用来生成摘要
        keysentences = tr4s.get_key_sentences(num=3, sentence_min_len=6)
        return keysentences
    
    
    def keywords_textrank(text):
        keywords = jieba.analyse.textrank(text, topK=6)
        return keywords
    
    
    if __name__ == "__main__":
        text = "来源:中国科学报本报讯(记者肖洁)又有一位中国科学家喜获小行星命名殊荣!4月19日下午,中国科学院国家天文台在京举行“周又元星”颁授仪式," \
               "我国天文学家、中国科学院院士周又元的弟子与后辈在欢声笑语中济济一堂。国家天文台党委书记、" \
               "副台长赵刚在致辞一开始更是送上白居易的诗句:“令公桃李满天下,何须堂前更种花。”" \
               "据介绍,这颗小行星由国家天文台施密特CCD小行星项目组于1997年9月26日发现于兴隆观测站," \
               "获得国际永久编号第120730号。2018年9月25日,经国家天文台申报," \
               "国际天文学联合会小天体联合会小天体命名委员会批准,国际天文学联合会《小行星通报》通知国际社会," \
               "正式将该小行星命名为“周又元星”。"
        #关键词抽取
        keywords=keywords_extraction(text)
        print(keywords)
    
        #关键短语抽取
        keyphrases=keyphrases_extraction(text)
        print(keyphrases)
    
        #关键句抽取
        keysentences=keysentences_extraction(text)
        print(keysentences)

    运行结果:

    (2)基于jieba的TextRank算法实现

    if __name__ == "__main__":
        text = "来源:中国科学报本报讯(记者肖洁)又有一位中国科学家喜获小行星命名殊荣!4月19日下午,中国科学院国家天文台在京举行“周又元星”颁授仪式," \
               "我国天文学家、中国科学院院士周又元的弟子与后辈在欢声笑语中济济一堂。国家天文台党委书记、" \
               "副台长赵刚在致辞一开始更是送上白居易的诗句:“令公桃李满天下,何须堂前更种花。”" \
               "据介绍,这颗小行星由国家天文台施密特CCD小行星项目组于1997年9月26日发现于兴隆观测站," \
               "获得国际永久编号第120730号。2018年9月25日,经国家天文台申报," \
               "国际天文学联合会小天体联合会小天体命名委员会批准,国际天文学联合会《小行星通报》通知国际社会," \
               "正式将该小行星命名为“周又元星”。"
    
        # 基于jieba的textrank算法实现
        keywords=keywords_textrank(text)
        print(keywords)

    运行结果:

    (3)基于SnowNLP的TextRank算法实现

        # 基于SnowNLP的textrank算法实现
        snlp=SnowNLP(text)
        print(snlp.keywords(6))  #关键词抽取
        print(snlp.summary(3))   #关键句抽取

    运行结果:

    4、PageRank算法与TextRank算法的区别

    • PageRank算法根据网页之间的链接关系构造网络,TextRank算法根据词之间的共现关系构造网络;
    • PageRank算法构造的网络中的边是有向无权边,TextRank算法构造的网络中的边是无向有权边。

     

    参考:TextRank算法的基本原理及textrank4zh使用实例

     

    交流学习资料共享欢迎入QQ群:955817470​​​​​​​

     

    展开全文
  • textrank作为文档关键字提取的常用算法,python将textrank封装了对象,可直接使用
  • TextRank算法是什么?基于TextRank算法进行关键词抽取 TextRank可以用于获得文章的关键词或者信息摘要。 TextRank 算法是一种用于文本的基于图的排序算法。其基本思想来源于谷歌的PageRank算法(其原理在本文...

    TextRank算法是什么?基于TextRank算法进行关键词抽取

    TextRank可以用于获得文章的关键词或者信息摘要。

    TextRank 算法是一种用于文本的基于图的排序算法。其基本思想来源于谷歌的 PageRank算法(其原理在本文在下面), 通过把文本分割成若干组成单元(单词、句子)并建立图模型, 利用投票机制对文本中的重要成分进行排序, 仅利用单篇文档本身的信息即可实现关键词提取、文摘。和 LDA、HMM 等模型不同, TextRank不需要事先对多篇文档进行学习训练, 因其简洁有效而得到广泛应用。

     

    TextRank

    类似于PageRank的思想,将文本中的 语法 单元 视作图中的节点,如果两个语法单元存在一定语法关系(例如共现),则这两个语法单元在图中就会有一条边相互连接,通过一定的迭代次数,最终不同的节点会有不同的权重,权重高的语法单元可以作为关键词。参考论文:Rada Mihalcea的《TextRankBring Order into texts》。

    节点的权重不仅依赖于它的入度结点,还依赖于这些入度结点的权重,入度结点越多,入度结点的权重越大,说明这个结点的权重越高;图中任两点 Vi , Vj 之间边的权重为 wji , 对于一个给定的点 Vi, In(Vi) , Out(Vi) 为点 Vi 指向的点集合。

    TextRank迭代计算公式为,

    https://images0.cnblogs.com/blog2015/522886/201506/251855295174864.png

    其中, d 为阻尼系数, 取值范围为 0 1, 代表从图中某一特定点指向其他任意点的概率, 一般取值为 0.85。使用TextRank 算法计算图中各点的得分时, 需要给图中的点指定任意的初值, 并递归计算直到收敛, 即图中任意一点的误差率小于给定的极限值时就可以达到收敛, 一般该极限值取 0.0001。算法通用流程:

    应用到关键短语抽取:

    1. 预处理,首先进行分词和词性标注,将单个word作为结点添加到图中;

    2. 设置语法过滤器,将通过语法过滤器的词汇添加到图中;出现在一个窗口中的词汇之间相互形成一条边;

    3. 基于上述公式,迭代直至收敛;一般迭代20-30次,迭代阈值设置为0.0001

    4. 根据顶点的分数降序排列,并输出指定个数的词汇作为可能的关键词;

    5. 后处理,如果两个词汇在文本中前后连接,那么就将这两个词汇连接在一起,作为关键短语;

    其中,TextRank是为TextRank算法抽取关键词所定义的类。类在初始化时,默认加载了分词函数和词性标注函数tokenizer = postokenizer = jieba.posseg.dt、停用词表stop_words = self.STOP_WORDS.copy()、词性过滤集合pos_filt = frozenset(('ns', 'n', 'vn', 'v')),窗口span = 5(("ns", "n", "vn", "v"))表示词性为地名、名词、动名词、动词。

    首先定义一个无向有权图,然后对句子进行分词;依次遍历分词结果,如果某个词i满足过滤条件(词性在词性过滤集合中,并且词的长度大于等于2,并且词不是停用词),然后将这个词之后窗口长度为5范围内的词j(这些词也需要满足过滤条件),将它们两两(词i和词j)作为key,出现的次数作为value,添加到共现词典中;

    然后,依次遍历共现词典,将词典中的每个元素,key = (词i,词j),value = i和词j出现的次数,其中词i,词j作为一条边起始点和终止点,共现的次数作为边的权重,添加到之前定义的无向有权图中。

    然后对这个无向有权图进行迭代运算textrank算法,最终经过若干次迭代后,算法收敛,每个词都对应一个指标值;

    如果设置了权重标志位,则根据指标值值对无向有权图中的词进行降序排序,最后输出topK个词作为关键词;

    def textrank(self, sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'), withFlag=False):

     

        self.pos_filt = frozenset(allowPOS)

        # 定义无向有权图

        g = UndirectWeightedGraph()

        # 定义共现词典

        cm = defaultdict(int)

        # 分词

        words = tuple(self.tokenizer.cut(sentence))

        # 依次遍历每个词

        for i, wp in enumerate(words):

            # i 满足过滤条件

            if self.pairfilter(wp):

                # 依次遍历词i 之后窗口范围内的词

                for j in xrange(i + 1, i + self.span):

                    # j 不能超出整个句子

                    if j >= len(words):

                        break

                    # j不满足过滤条件,则跳过

                    if not self.pairfilter(words[j]):

                        continue

                    # 将词i和词j作为key,出现的次数作为value,添加到共现词典中

                    if allowPOS and withFlag:

                        cm[(wp, words[j])] += 1

                    else:

                        cm[(wp.word, words[j].word)] += 1

        # 依次遍历共现词典的每个元素,将词i,词j作为一条边起始点和终止点,共现的次数作为边的权重

        for terms, w in cm.items():

            g.addEdge(terms[0], terms[1], w)

       

        # 运行textrank算法

        nodes_rank = g.rank()

       

        # 根据指标值进行排序

        if withWeight:

            tags = sorted(nodes_rank.items(), key=itemgetter(1), reverse=True)

        else:

            tags = sorted(nodes_rank, key=nodes_rank.__getitem__, reverse=True)

     

        # 输出topK个词作为关键词

        if topK:

            return tags[:topK]

        else:

            return tags

    其中,无向有权图的的定义及实现是在UndirectWeightedGraph类中实现的。根据UndirectWeightedGraph类的初始化函数__init__,我们可以发现,所谓的无向有权图就是一个词典,词典的key是后续要添加的词,词典的value,则是一个由(起始点,终止点,边的权重)构成的三元组所组成的列表,表示以这个词作为起始点的所有的边。

    无向有权图添加边的操作是在addEdge函数中完成的,因为是无向图,所以我们需要依次将start作为起始点,end作为终止点,然后再将start作为终止点,end作为起始点,这两条边的权重是相同的。

    def addEdge(self, start, end, weight):

        # use a tuple (start, end, weight) instead of a Edge object

        self.graph[start].append((start, end, weight))

        self.graph[end].append((end, start, weight))

    执行textrank算法迭代是在rank函数中完成的。

    首先对每个结点赋予相同的权重,以及计算出该结点的所有出度的次数之和;

    然后迭代若干次,以确保得到稳定的结果;

    在每一次迭代中,依次遍历每个结点;对于结点n,首先根据无向有权图得到结点n的所有
    入度结点(对于无向有权图,入度结点与出度结点是相同的,都是与结点n相连的结点),在前面我们已经计算出这个入度结点的所有出度的次数,而它对于结点n的权值的贡献等于它本身的权值 乘以 它与结点n的共现次数 / 这个结点的所有出度的次数 ,将各个入度结点得到的权值相加,再乘以一定的阻尼系数,即可得到结点n的权值;

    迭代完成后,对权值进行归一化,并返回各个结点及其对应的权值。

    def rank(self):

        ws = defaultdict(float)

        outSum = defaultdict(float)

     

        wsdef = 1.0 / (len(self.graph) or 1.0)

        # 初始化各个结点的权值

        # 统计各个结点的出度的次数之和

        for n, out in self.graph.items():

            ws[n] = wsdef

            outSum[n] = sum((e[2] for e in out), 0.0)

     

        # this line for build stable iteration

        sorted_keys = sorted(self.graph.keys())

        # 遍历若干次

        for x in xrange(10):  # 10 iters

            # 遍历各个结点

            for n in sorted_keys:

                s = 0

                # 遍历结点的入度结点

                for e in self.graph[n]:

                    # 将这些入度结点贡献后的权值相加

                    # 贡献率 = 入度结点与结点n的共现次数 / 入度结点的所有出度的次数

                    s += e[2] / outSum[e[1]] * ws[e[1]]

                # 更新结点n的权值

                ws[n] = (1 - self.d) + self.d * s

     

        (min_rank, max_rank) = (sys.float_info[0], sys.float_info[3])

     

        # 获取权值的最大值和最小值

        for w in itervalues(ws):

            if w < min_rank:

                min_rank = w

            if w > max_rank:

                max_rank = w

     

        # 对权值进行归一化

        for n, w in ws.items():

            # to unify the weights, don't *100.

            ws[n] = (w - min_rank / 10.0) / (max_rank - min_rank / 10.0)

     

        return ws

     

    参考:textrank算法原理与提取关键词、自动提取摘要PYTHON

    参考:textrank算法

    参考:aopu自然语言处理

    展开全文
  • textrank4zh模块源码解读2 textrank4zh模块的使用2.1 textrank4zh模块的安装2.2 textrank4zh的使用实例1)提取关键词、关键短语和关键句2)展示textrank4zh模块的三种分词模式的效果 TextRank算法是一种文本排序...
  • 一.NLG文本生成任务 文本生成NLG,不同于文本理解NLU(例如分词、词向量、分类、实体提取),是重在文本生成的...现在,我记录的是textrank,一种使用比较广泛的抽取式关键句提取算法。 二、TextRank前世今生 ...
  • Py之textrank4zh:textrank4zh的简介、安装、使用方法之详细攻略 目录 textrank4zh的简介 原理 关键词提取 关键短语提取 摘要生成 textrank4zh的安装 textrank4zh的使用方法 textrank4zh的简介...
  • TextRank4ZH

    2016-11-17 17:30:21
    TextRank;关键词提取;摘要提取
  • textrank算法-python实现

    2018-04-03 10:18:02
    这是一个基于python实现的textrank算法 python版本:2.7.14 文件夹‘candidates’和‘conferences’是数据集 文件夹‘keywords-candidates-textrank’和‘可以words-conferences-textrank’存放运行结果 运行: ...
  • W2V_TextRank 简介 文本自动摘要算法:用Word2Vec改进的TextRank算法 结果对比:在5000个中文文本样本上的结果 评价指标 ROUGE1&2 ROUGE SU4 R&F 使用说明 可以直接在命令行中运行编译好的jar包,jar包及训练好的...
  • TextRank算法

    2019-05-05 15:40:34
    textrank = analyse.textrank # 原始文本 text = "非常线程是程序执行时的最小单位,它是进程的一个执行流,\ 是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\ 线程间共享进程的所有资源,每个线程有...
  • TextRank-Keyword-Extraction:在使用词形去除预处理文本,过滤掉不需要的词性和其他技术之后,使用TextRank算法提取关键字
  • 用python写了一个简单版本的textrank,实现提取关键词的功能。 import numpy as np import jieba import jieba.posseg as pseg class TextRank(object): def __init__(self, sentence, window, alpha, iternum):...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,624
精华内容 12,249
关键字:

textrank