赞
踩
好的,那下面我们就用TextRank算法,以及按照上面的流程,做一个新闻自动摘要的小案例。
参考了一篇用TextRank做英文新闻摘要的文章。
1、文章:《手把手|基于TextRank算法的文本摘要(附Python代码)》
2、github地址
文档的原网页:
实践的github
好,那就开始。
首先把文档读入,放在列表中,可以看到,有些句子已经被划分出来了。
['信息量巨大!易会满首秀,直面科创板8大问题,对散户加速入场笑而不语……',
'每日经济新闻',
'02-2717:56',
'每经编辑:郭鑫 王晓波',
'图片来源:新华社记者 李鑫 摄',
'易会满上任一个月,还没有在公开场合说过一句话。',
'2月27日下午三点半开始,XX出席其首场新闻发布会,离发布会开始前两小时现场已经座无虚席,只等XX来到现场。此外,XX、XX等也共同出席。',
...]
不过通过观察,我们可以发现存在两个问题:
一是以[。?!;]作为句子的分隔符,那么列表中的每个字符串元素中可能有多个句子;
二是每个字符串元素可能以[:,]结尾,也就是说可能是一个不完整的句子。
考虑到这只是一个小案例,所以就没花太多时间,仅仅处理一下第一个问题,把句子按照[。?!;]进行划分,如果字符串元素是不完整的句子,那也作为一句。
import numpy as np import pandas as pd import re,os,jieba from itertools import chain """第一步:把文档划分成句子""" # 文档所在的文件夹 c_root = os.getcwd()+os.sep+"cnews"+os.sep sentences_list = [] for file in os.listdir(c_root): fp = open(c_root+file,'r',encoding="utf8") for line in fp.readlines(): if line.strip(): # 把元素按照[。!;?]进行分隔,得到句子。 line_split = re.split(r'[。!;?]',line.strip()) # [。!;?]这些符号也会划分出来,把它们去掉。 line_split = [line.strip() for line in line_split if line.strip() not in ['。','!','?',';'] and len(line.strip())>1] sentences_list.append(line_split) sentences_list = list(chain.from_iterable(sentences_list)) print("前10个句子为:\n") print(sentences_list[:10])
前10个句子为:
['信息量巨大', '易会满首秀,直面科创板8大问题,对散户加速入场笑而不语……', '每日经济新闻', '02-2717:56', '每经编辑:郭鑫 王晓波', '图片来源:新华社记者 李鑫 摄', '易会满上任一个月,还没有在公开场合说过一句话', '2月27日下午三点半开始,中XX出席其首场新闻发布会,离发布会开始前两小时现场已经座无虚席,只等XX来到现场', '此外,XX、XX等也共同出席', '这可能是这个月国内关注的人最多的一场新闻发布会了']
文本预处理包括去除停用词和非汉字字符,并进行分词。处理的过程要保证处理之后的句子的数量和处理之前的一样,因为后面我们计算了每个句子的textrank值之后,需要根据textrank值的大小,取出相应的句子作为摘要。
比如 ‘02-2717:56’ 这个句子整个被过滤了,那就令这个句子为[],下面也会给它一个句子的向量表示,只是元素都为0。
"""第二步:文本预处理,去除停用词和非汉字字符,并进行分词""" #创建停用词列表 stopwords = [line.strip() for line in open('./stopwords.txt',encoding='UTF-8').readlines()] # 对句子进行分词 def seg_depart(sentence): # 去掉非汉字字符 sentence = re.sub(r'[^\u4e00-\u9fa5]+','',sentence) sentence_depart = jieba.cut(sentence.strip()) word_list = [] for word in sentence_depart: if word not in stopwords: word_list.append(word) # 如果句子整个被过滤掉了,如:'02-2717:56'被过滤,那就返回[],保持句子的数量不变 return word_list sentence_word_list = [] for sentence in sentences_list: line_seg = seg_depart(sentence) sentence_word_list.append(line_seg) print("一共有",len(sentences_list),'个句子。\n') print("前10个句子分词后的结果为:\n",sentence_word_list[:10]) # 保证处理后句子的数量不变,我们后面才好根据textrank值取出未处理之前的句子作为摘要。 if len(sentences_list) == len(sentence_word_list): print("\n数据预处理后句子的数量不变!")
一共有 347 个句子。
前10个句子分词后的结果为:
[['信息量'],
['易会', '满首秀', '直面', '科创板', '散户', '加速', '入场', '笑', '不语'],
['每日', '经济', '新闻'],
[],
['每经', '编辑', '郭鑫', '王晓波'],
['图片', '来源', '李鑫', '摄'],
['易会', '上任', '一个月', '公开场合', '说', '一句', '话'],...]
数据预处理后句子的数量不变!
从这里下载了金融新闻word2vec词向量:https://github.com/Embedding/Chinese-Word-Vectors。
词向量是300维的,字和词语都有。我们把词向量加载进来,做成一个字典,共有467140个词语或字。
"""第三步:准备词向量"""
word_embeddings = {}
f = open('./sgns.financial.char', encoding='utf-8')
for line in f:
# 把第一行的内容去掉
if '467389 300\n' not in line:
values = line.split()
# 第一个元素是词语
word = values[0]
embedding = np.asarray(values[1:], dtype='float32')
word_embeddings[word] = embedding
f.close()
print("一共有"+str(len(word_embeddings))+"个词语/字。")
一共有467140个词语/字。
WordAVG也就是先得到句子中的所有词语的词向量,然后求词向量的平均,作为该句子的向量表示。WordAVG可以用来计算句子的相似度。
"""第四步:得到词语的embedding,用WordAVG作为句子的向量表示"""
sentence_vectors = []
for i in sentence_word_list:
if len(i)!=0:
# 如果句子中的词语不在字典中,那就把embedding设为300维元素为0的向量。
# 得到句子中全部词的词向量后,求平均值,得到句子的向量表示
v = sum([word_embeddings.get(w, np.zeros((300,))) for w in i])/(len(i))
else:
# 如果句子为[],那么就向量表示为300维元素为0个向量。
v = np.zeros((300,))
sentence_vectors.append(v)
"""第五步:计算句子之间的余弦相似度,构成相似度矩阵"""
sim_mat = np.zeros([len(sentences_list), len(sentences_list)])
from sklearn.metrics.pairwise import cosine_similarity
for i in range(len(sentences_list)):
for j in range(len(sentences_list)):
if i != j:
sim_mat[i][j] = cosine_similarity(sentence_vectors[i].reshape(1,300), sentence_vectors[j].reshape(1,300))[0,0]
print("句子相似度矩阵的形状为:",sim_mat.shape)
句子相似度矩阵的形状为: (347, 347)
以句子为节点、相似性得分为转移概率,构建图结构,然后迭代得到句子的TextRank分数。
对句子按照TextRank值进行降序排序,取出排名最靠前的10个句子作为摘要。
"""第六步:迭代得到句子的textrank值,排序并取出摘要""" import networkx as nx # 利用句子相似度矩阵构建图结构,句子为节点,句子相似度为转移概率 nx_graph = nx.from_numpy_array(sim_mat) # 得到所有句子的textrank值 scores = nx.pagerank(nx_graph) # 根据textrank值对未处理的句子进行排序 ranked_sentences = sorted(((scores[i],s) for i,s in enumerate(sentences_list)), reverse=True) # 取出得分最高的前10个句子作为摘要 sn = 10 for i in range(sn): print("第"+str(i+1)+"条摘要:\n\n",ranked_sentences[i][1],'\n')
第1条摘要:... 第2条摘要:... 第3条摘要:... 第4条摘要:... 第5条摘要:... 第6条摘要:... 第7条摘要:... 第8条摘要:... 第9条摘要:... 第10条摘要:...
声明:因文本中包含敏感信息,故省略
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。