Python 实现英文新闻摘要自动提取 (2)

TextRank算法完成摘要提取

一、实验简介

1.1 实验内容

上节实验我们完成了一个简单的“关键字提取”算法,初步了解了自然语言处理。本节实验,我们将实现TextRank算法完成新闻摘要提取。

1.2 实验知识点

  • Python基础知识
  • TextRank算法

1.3 实验环境

  • Xfce终端
  • python3

1.4 实验结果

我们最终获取了与上一节实验不同摘要

The PHE website and app has a quiz that gives users a health score based on their lifestyle habits by asking questions such as, "Which snacks do you eat in a normal day?"

The campaign's clinical adviser, Prof Muir Gray, said it was about trying to make people have a different attitude to an "environmental problem".

二、TextRank算法介绍

我们在上一次实验当中运用了比较基础的“关键字提取”法来完成我们的摘要提取功能,但是我们需要优化我们的算法。这次我们使用TextRank算法来完成摘要提取工作。

关于TextRank的论文请看这里: TextRank: Bring Order into Texts

在介绍 TextRank 之前我们首先需要了解 PageRank 算法。

2.1 PageRank算法

PageRank 是根据网页之间相互的超链接计算网页重要性 的技术,是Google的创始人拉里·佩奇和谢尔盖·布林于1998年在斯坦福大学发明了这项技术。

提到 重要性 我们就会联想到我们上一个实验也计算了每一个单词的 重要性 ,但是在PageRank算法中是为每个页面计算 重要性 ,而TextRank对PageRank算法做了改进,使其可以计算每一个 句子 的 重要性 。

我们通过一个例子来理解PageRank。

此处输入图片的描述

我们可以看到这个图中有不同颜色的球,代表的是不同的页面,而图中的箭头代表的是 超链接 。如图中D球指向A球,代表的就是D界面有指向A界面的超链接,相当于是D界面“推荐”了A界面。PageRank就是基于“推荐”的算法。

我们看到各个界面,既有推荐出去 (Out) 的箭头,也有别的界面推荐进来 (In) 的箭头。于是我们就可以列出一张邻接矩阵来描述整张图(忽略紫色的球!)。

0代表没有推荐,1代表的是推荐。

每一代表的是你推荐的页面 (Out)。如A列,代表的就是A推荐的页面。如表格所描述的,A谁也没有推荐。

每一代表的是谁推荐了你 (In)。如A行,代表的就是推荐A的页面。如表格所描述的,D推荐了A。

In\Out A BCDEF
A 0 00100
B 0 01111
C 0 10000
D 0 00010
E 0 00001
F 0 00010

有了这张邻接矩阵作为基础,我们就能够计算PageRank的核心:每一个页面的分数 S

此处输入图片的描述

Vi 代表的是每一个顶点,及页面。

d 代表的是一个阻尼常数 (0<d<1),用来确保每一个页面都至少有 (1-d)的分数。

In(Vi) 代表的是推荐Vi的页面。

Out(Vi) 代表的是Vi推荐的页面。

|Out(Vi)| 代表的是Vi推荐页面的数量。

 符号相对复杂请参考求和符号∑

我们会发现,每一个页面的分数 S( Vi ) 都是依赖于别的页面的分数 S( Vj ) 的。我们需要对每个页面的分数进行初始化。初始化的数字并不重要,因为通过数学可以证明初始化的值对于最终的结果并不影响,只不过会影响算法迭代的次数。我们这里为了计算方便,把初始的 S 都设为 1 。 d 设为 0.85 (参考 S. Brin, L Page 1998年的论文)

我们来尝试求一求 页面 B 的分数。有三个页面D,E,F推荐页面B。按照顺序计算他们的值。

S(VB) = (1 - 0.85) + 0.85 * ( (1 / 2 * 1) + (1 / 2 * 1 ) + (1 / 2 * 1 ))

S(VB) 的值为1.425

就这样一步一步算出每一个顶点的值,然后接着从A页面开始继续算,一遍一遍迭代,直到每个页面的分数都不再变化为止。这样,我们就得到了每一个页面的评分 S

2.2 TextRank算法

当我们把PageRank应用到我们的文本当中去的时候,我们首先会发现的问题是,句子和句子之间 如何相互“推荐”?

TextRank给出了相应的算法。

此处输入图片的描述

注意!这里 S 代表的不是PageRank中的分数,它代表的是 Sentence 代表的是每一个句子。

Si 代表的是第 i 个句子。

wk 代表的是句子中第 k 个单词。

|Si| 代表的是句子中单词的个数。

{ wk| wk ∈ Si & wk ∈ Sj } 代表着同时在 Si 和 Sj 中出现的单词。

根据这个就可以求出两个句子之间的相似度,也就是推荐程度

举个例子。

I am a fool. A big fool. I like fool.

前两句句子当中都有的单词是 a 和 fool,两个单词。

第一句话和第三句话都有的单词是 I 和 fool。

后两句句子当中都有的单词是 fool .

第一句话长度是 4,第二句话长度是3, 第三句话长度是3.

Similarity(S1,S2) = 2 / ( log(3) + log(4) ) = 0.80
Similarity(S1,S3) = 2 / ( log(3) + log(3) ) = 0.91
Similarity(S2,S3) = 1 / ( log(3) + log(4) ) = 0.40

注意!

  • 两个句子的相似度没有指向性. 也就是说Similarity(S1,S2) = Similarity(S2,S1)
  • 相似度不再只有0 和 1 ,它是浮点数的集合。
相似度 第一句 第二句 第三句
第一句 None 0.80 0.91
第二句 0.80 None 0.40
第三句 0.91 0.40 None

我们写出来类似PageRank中的邻接矩阵。

在此基础上,我们可以应用新的PageRank算法来完成分数的计算

此处输入图片的描述

WS(Vi) 代表的是Vi这个页面的分数

d 代表的是一个阻尼常数 (0<d<1),用来确保每一个页面都至少有 (1-d)的分数。

In(Vi) 代表的是推荐Vi的页面。

Out(Vi) 代表的是Vi推荐的页面。

wji 代表的是 Vi 和 Vj 之间的相似度。

我们拿第一句句子作为例子,看一看它的得分。同样的,初始分数都是 1 。

WS(V1) = (1 - 0.85) + 0.85 * 
( /*第二句句子*/ (0.80 * 1) / (0.80 + 0.40) + 
  /*第三句句子*/ (0.91 * 1) / (0.91 + 0.40) ) = 1.30

至此我们进一步迭代,计算出第二句和第三句的 分数 ,然后继续从第一句开始计算。直到最终每一句的分数不再变化为止。

三、实验步骤

3.1 准备工作

弄清楚了原理,我们要开始写代码了。首先导入我们需要的包。基本和实验一需要的包是一样的。

from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords
import math
from itertools import product, count
from string import punctuation
from heapq import nlargest

stopwords = set(stopwords.words('english') + list(punctuation))

3.2 计算相似性

这个函数计算两个句子之间的相似性。有关相似性的知识,请看上文的算法介绍。

"""
传入两个句子
返回这两个句子的相似度
"""
def calculate_similarity(sen1, sen2):
    # 设置counter计数器
    counter = 0
    for word in sen1:
        if word in sen2:
            counter += 1
    return counter / (math.log(len(sen1)) + math.log(len(sen2)))

3.3 创建相似度邻接矩阵


"""
传入句子的列表
返回各个句子之间相似度的图
(邻接矩阵表示)
"""
def create_graph(word_sent):
    num = len(word_sent)
    # 初始化表
    board = [[0.0 for _ in range(num)] for _ in range(num)]

    for i, j in product(range(num), repeat=2):
        if i != j:
            board[i][j] = calculate_similarity(word_sent[i], word_sent[j])
    return board

3.4 根据PageRank算法,算出句子分数

"""
输入相似度邻接矩阵
返回各个句子的分数
"""
def weighted_pagerank(weight_graph):
    # 把初始的分数值设置为0.5
    scores = [0.5 for _ in range(len(weight_graph))]
    old_scores = [0.0 for _ in range(len(weight_graph))]

    # 开始迭代
    while different(scores, old_scores):
        for i in range(len(weight_graph)):
            old_scores[i] = scores[i]

        for i in range(len(weight_graph)):
            scores[i] = calculate_score(weight_graph, scores, i)
    return scores

"""
判断前后分数有没有变化
这里认为前后差距小于0.0001
分数就趋于稳定
"""
def different(scores, old_scores):
    flag = False
    for i in range(len(scores)):
        if math.fabs(scores[i] - old_scores[i]) >= 0.0001:
            flag = True
            break
    return flag


"""
根据公式求出指定句子的分数
"""
def calculate_score(weight_graph, scores, i):
    length = len(weight_graph)
    d = 0.85
    added_score = 0.0


    for j in range(length):
        fraction = 0.0
        denominator = 0.0
        # 先计算分子
        fraction = weight_graph[j][i] * scores[j]
        # 计算分母
        for k in range(length):
            denominator += weight_graph[j][k]
        added_score += fraction / denominator
    # 算出最终的分数
    weighted_score = (1 - d) + d * added_score

    return weighted_score

3.5 找出分数最高的两个句子

def Summarize(text,n):
    # 首先分出句子
    sents = sent_tokenize(text)
    # 然后分出单词
    # word_sent是一个二维的列表
    # word_sent[i]代表的是第i句
    # word_sent[i][j]代表的是
    # 第i句中的第j个单词
    word_sent = [word_tokenize(s.lower()) for s in sents]

    # 把停用词去除
    for i in range(len(word_sent)):
        for word in word_sent[i]:
            if word in stopwords:
                word_sent[i].remove(word)
    similarity_graph = create_graph(word_sent)
    scores = weighted_pagerank(similarity_graph)
    sent_selected = nlargest(n, zip(scores, count()))
    sent_index = []
    for i in range(n):
        sent_index.append(sent_selected[i][1])
    return [sents[i] for i in sent_index]

3.6 运行程序

最后加上我们的main:

if __name__ == '__main__':
    # 可以替换为别的新闻
    with open("news.txt", "r") as myfile:
        text = myfile.read().replace('\n' , '')
    # 可以更改参数 2 来获得不同长度的摘要。
    # 但是摘要句子数量不能多于文本本身的句子数。
    print(Summarize(text, 2)

这里我们提供了一个样本news.txt。可以在命令行中输入如下代码来获取。

wget http://labfile.oss.aliyuncs.com/courses/741/news.txt

四、实验总结

我们来对比一下两个算法获取的摘要

关键字提取算法

"Modern life is dramatically different to even 30 years ago," Prof Gray told Radio 4's Today programme, "people now drive to work and sit at work."

"The How Are You Quiz will help anyone who wants to take a few minutes to take stock and find out quickly where they can take a little action to make a big difference to their health."

TextRank算法

The PHE website and app has a quiz that gives users a health score based on their lifestyle habits by asking questions such as, "Which snacks do you eat in a normal day?"

The campaign's clinical adviser, Prof Muir Gray, said it was about trying to make people have a different attitude to an "environmental problem".

结论是两个算法的效果都一般,都没能把主题句找出来。相比较而言,比较简单的关键字提取算法可能选出的摘要要更加贴切一些。但是我们不能就这一个特例就断定TextRank算法不好。大家可以自己上传一个txt来对比两个算法的优劣。

五、实验代码

在命令行中输入

wget http://labfile.oss.aliyuncs.com/courses/741/NewsSummary2.py
本课程隶属于自然语言处理(NLP)实战系列。自然语言处理(NLP)是数据科学里的一个分支,它的主要覆盖的内容是:以一种智能与高效的方式,对文本数据进行系统化分析、理解与信息提取的过程。通过使用NLP以及它的组件,我们可以管理非常大块的文本数据,或者执行大量的自动化任务,并且解决各式各样的问题,如自动摘要,机器翻译,命名实体识别,关系提取,情感分析,语音识别,以及主题分割等等。一般情况下一个初级NLP工程师的工资从15万-35万不等,所以掌握NLP技术,对于人工智能学习者来讲是非常关键的一个环节。【超实用课程内容】 课程从自然语言处理的基本概念与基本任务出发,对目前主流的自然语言处理应用进行全面细致的讲解,包括文本分类,文本摘要提取,文本相似度,文本情感分析,文本特征提取等,同时算法方面包括经典算法与深度学习算法的结合,例如LSTM,BiLSTM等,并结合京东电商评论分类、豆瓣电影摘要提取、今日头条舆情挖掘、饿了么情感分析等过个案例,帮助大家熟悉自然语言处理工程师在工作中会接触到的常见应用的实施的基本实施流程,从0-1入门变成自然语言处理研发工程师。 【课程如何观看?】 PC端:https://edu.csdn.net/course/detail/25649 移动端:CSDN 学院APP(注意不是CSDN APP哦)本课程为录播课,课程2年有效观看时长,大家可以抓紧时间学习后一起讨论哦~【学员专享增值服务】 源码开放课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化下载方式:电脑登录https://edu.csdn.net/course/detail/25649,点击右下方课程资料、代码、课件等打包下载通过第二课时下载材料
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值