当前位置:   article > 正文

基于Python的抽取式文本自动摘要的实现

基于python的抽取式文本自动摘要的实现

资源下载地址:https://download.csdn.net/download/sheziqiong/85736065
资源下载地址:https://download.csdn.net/download/sheziqiong/85736065

核心思想与算法描述

文本摘要有两种实现方式,一种是基于生成的方式,通过使用RNN等神经网络进实现,另外一种是抽取的方式。

本次作业重点关注基于抽取式的文本自动摘要的实现,以及实现的算法——textrank

pagerank算法应用于谷歌等搜索引擎中,通过网页链接的数量和质量来初略估计网页的重要性,从而对网页进行排名。textrank是基于pagerank算法的一种改进,它利用一篇文章内部词语共同出现的语义信息即可对一篇文章进行关键词抽取和关键句抽取,并且不需要依赖于语料库等训练数据。

下面从关键词抽取和关键句抽取两方面进行介绍。

关键词抽取

使用textrank进行关键词抽取的核心思想为利用词之间的相邻关系来构建一个词网络,然后使用pagerank的方式进行迭代计算,得到每个节点的权值,一个节点的权值越高其重要程度越高,故而得到关键词。

但可以发现,一个句子中有一些常用的词,如“的”、“了”等出现频率非常高,这类词也被称为停用词,尽管出现频率高但不可能作为关键词,所以一个句子总是将停用词去掉后再进行关键词的抽取。

具体算法描述如下:

  1. 给定输入句子 i n p u t = w 1 w 2 w 3 . . . w n input=w_1w_2w_3...w_n input=w1w2w3...wn

  2. 使用jieba进行分词,得到输入句子的词序列 i n p u t S e q = [ w 1 , w 2 , . . . , w n ] inputSeq=[w_1,w_2,...,w_n] inputSeq=[w1,w2,...,wn]

  3. 加载停用词表,对 i n p u t S e q inputSeq inputSeq中的词进行过滤,经过停用词表过滤后的词序列为 w o r d S e q = [ w 1 , w 2 , . . . , w k ] wordSeq=[w_1,w_2,...,w_k] wordSeq=[w1,w2,...,wk]

    由于在此步骤中主要操作可以描述为:查询一个给定词 w w w是否在一个词典中,所以使用了字典树数据结构来进行优化,避免了一次查询需要扫描一次词典的低效操作。

  4. 计算邻接矩阵 T i , j T_{i,j} Ti,j,其中 T i , j = k T_{i,j}=k Ti,j=k表示从词 i i i转移到词 j j j的次数为 k k k,为了定义转移使用了一个共现窗口来定义,窗口的大小默认定义为 3 3 3。那么如果 ∣ i − j ∣ ≤ 3 |i-j|\le 3 ij3,则 w i w_i wi可以转移到 w j w_j wj w j w_j wj也可以转移到 w i w_i wi,也就是说 T T T是一个对称矩阵。

    在完成转移次数的计算后,对 T T T进行归一化计算 T i , j = T i , j ∑ k = 1 n T i , k T_{i,j}=\frac{T_{i,j}}{\sum_{k=1}^{n}T_{i,k}} Ti,j=k=1nTi,kTi,j,即 T i , j T_{i,j} Ti,j为从 w i w_i wi w j w_j wj转移的概率。

  5. 通过如下公式对词网络进行迭代计算,直到收敛:
    v a l i = ( 1 − d ) + d × ∑ j ∈ i n ( i ) W j , i × v a l j ∑ k ∈ o u t ( j ) W j , k = ( 1 − d ) + d × ∑ j ∈ i n ( i ) T i , j v a l j val_i=(1-d)+d\times \sum_{j\in in(i)}\frac{W_{j,i}\times val_j}{\sum_{k\in out(j)W_{j,k}}} \\=(1-d)+d\times \sum_{j\in in(i)}T_{i,j}val_j vali=(1d)+d×jin(i)kout(j)Wj,kWj,i×valj=(1d)+d×jin(i)Ti,jvalj
    为了判断收敛,我通过计算迭代前后两个 r a n k rank rank相邻的二范数之差,如果两者之差小于 0.0001 0.0001 0.0001则认为 r a n k rank rank向量收敛

  6. 根据 r a n k rank rank向量,选择 r a n k rank rank值最大的几个词当作本篇文章的关键词。

关键句抽取

基于textrank的关键句抽取核心思想与上述关键词抽取基本相同,在关键句抽取中以句子作为单位,而不是以此作为单位。

此时,邻接矩阵 T i , j T_{i,j} Ti,j不再是词 i i i转移到词 j j j的概率,而是句子 i i i与句子 j j j的相似性,关于句子 i i i与句子 j j j的相似度定义为:
s i m i l a r i t y i , j = ∣ { w k ∣ w k ∈ S i ∧ w k ∈ S j } ∣ log ⁡ ( ∣ s i ∣ ) × log ⁡ ( ∣ s j ∣ ) similarity_{i,j}=\frac{|\{w_k|w_k \in S_i \wedge w_k \in S_j\}|}{\log(|s_i|)\times \log(|s_j|)} similarityi,j=log(si)×log(sj){wkwkSiwkSj}
这一相似度的定义虽然在某种程度上使两个句子之间建立了联系,但是没有考虑到词语与词语之间的词性相近等因素,如在句子 S i S_i Si中有一个词"巨大",而在 S j S_j Sj中有一个词"庞大",由于这两个词不同所以对相似度没有正贡献。但是两个词的含义非常相近,应该考虑其对相似度的贡献,而不是由于词不同而简单省略。

因此,在此处对传统的textrank算法进行一个改进,转而使用word2vec词向量表示来计算句子的相似度,词向量能够考虑到词与词之间的距离,从而能更好地解决句子之间相似度的计算问题。

考虑使用一个 n n n维的向量来表示词,那么定义一个句子 S = w 1 w 2 . . . w k S=w_1w_2...w_k S=w1w2...wk n n n维句向量:
v e c = 1 k ∑ i = 1 k v e c w i vec=\frac{1}{k}\sum_{i=1}^kvec_{w_i} vec=k1i=1kvecwi
式子中 v e c w i vec_{w_i} vecwi w i w_i wi的词向量,即对句子中所有词的向量做一个简单的平均,得到句子的句向量。在得到句子的句向量后,句子的相似度定义为:
s i m i l a r i t y i , j = ∑ k = 1 n v e c i k × v e c j k ( ∑ k = 1 n v e c i k 2 ) × ( ∑ k = 1 n v e c j k 2 ) similarity_{i,j}=\frac{\sum_{k=1}^nvec_{ik}\times vec_{jk}}{\sqrt(\sum^n_{k=1} vec_{ik}^2) \times \sqrt(\sum^n_{k=1} vec_{jk}^2) } similarityi,j=( k=1nvecik2)×( k=1nvecjk2)k=1nvecik×vecjk
即两个句子的相似度定义为两个句向量的点乘除于两个相邻二范数的乘积。

具体算法描述如下:www.biyezuopin.vip

  1. 给定输入文章 p = s 1 s 2 . . . s n p=s_1s_2...s_n p=s1s2...sn
  2. 使用正则表达式,将给定的文章分成句子列表 p = [ s 1 , s 2 , . . . s n ] p=[s_1,s_2,...s_n] p=[s1,s2,...sn]
  3. 对于每个句子 s i s_i si,对其进行分词和停用词过滤,得到 s 1 = [ w 1 , w 2 , . . . , w n ] s_1=[w_1,w_2,...,w_n] s1=[w1,w2,...,wn]
  4. 计算每个句子 s i s_i si的句向量 v e c i vec_i veci
  5. 计算转移矩阵 T i , j = k T_{i,j}=k Ti,j=k,其中 k k k为上述定义的相似度
  6. 使用同关键词抽取的迭代公式进行句子 r a n k rank rank值的计算,直到收敛
  7. 选择 r a n k rank rank值最高的一个句子作为关键句

系统主要模块流程

系统架构如下图所示

本系统基于django框架设计前后端web项目,可分为如下几个模块:

  • 网页前端模块,前端模块中可分为向后端提交数据结构和从后端获取数据接口
  • 后端响应模块,后端响应模块主要指django中的view函数模块,通过url指定view函数处理前端发送的请求事务
  • 算法模块,完成关键词和关键句的抽取工作

三个模块的基本关系如下图所示:

下面分别介绍各个模块的具体实现:

网页前端模块

导航栏部分

导航栏使用Flex弹性布局方式,导航栏内的元素进行两端对齐。左端元素为Logo,右端为用户相关内容。www.biyezuopin.vip

页面主体
样式

页面的主体为左右布局,实现左右布局的方式为Flex弹性布局。页面之中的各个小组件,诸如按钮,单选框,标题,输入框均采用bootstrap内置的样式。另外,不允许用户复制输入框以及输出框以外的内容。

DOM节点控制以及网络请求

DOM节点的控制使用JavaScript的经典库JQuery,当点击“提交”按钮的时候,通过JQuery获取文章输入框以及处理算法选择框的内容,获取内容之后,向后台发送Ajax请求,将文章内容以及处理方式发送到后台,获取后台的信息之后,对后台发送过来的内容进行分析,如果状态正常,则将摘要以及关键词现实在右边的对应方框之中。

         $('#btnEditSave').click(function () {
            let postDate = {};
            $('#errorMag').text('');

            $('#input_area').find('input, textarea').each(function () {

                let v = $(this).val();
                let n = $(this).attr('name');
                if (n === 'handle_method'){
                    if ($(this).prop('checked')) {
                        postDate[n] = v;
                    }
                } else{
                    postDate[n] = v;
                }

            });

            console.log(postDate);

            $.ajax({
                url:'/extract/',
                type:'POST',
                data:postDate,
                success:function (arg) {
                    console.log(arg);
                    console.log(typeof(arg));
                    var dict = JSON.parse(arg);
                    if(dict.status){
                        console.log(dict);
                        $('#output_area').find('#keyword').val(dict.keyword);
                        $('#output_area').find('#pdigest').val(dict.pdigest);
                    }else{
                        $('#errorMag').text(dict.message);
                    }
                }
            })

        })
    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

点击“清空”按钮,将所有框之中的内容进行清除

        //重置
        $('#clear_text').click(function () {
            $('#input_passage').val('');
            $('#pdigest').val('');
            $('#keyword').val('');
            $('#errorMag').text('');
             $("input[type=radio][name='handle_method'][value='text_rank']").prop("checked",true);
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

后端响应模块

因为使用前后端不分离的模式,通过Django的模板渲染显示前端页面,所以在settings.py修改以下内容

# 部署到服务器
ALLOWED_HOSTS = ['0x404.tech', 'www.0x404.tech',  'localhost', '127.0.0.1']

# 添加模板渲染
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# 静态资源访问
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

对访问的URL进行正则表达式方式的匹配,并与对应的Controller进行对应。

urls.py之中添加显示以下内容

urlpatterns = [
    re_path('admin/', admin.site.urls),
    re_path('^$', views.index),
    re_path('^extract/', views.extract)
]
  • 1
  • 2
  • 3
  • 4
  • 5

views.py之中对前端的请求进行处理

  • 主页面渲染

    def index(request):
        return render(request, 'index.html')
    
    • 1
    • 2
  • 关键词摘要请处理
    返回给前端页面json格式的数据,message表示错误信息,当处理失败的时候,前端通过后端传来的status以及message两个关键词进行相应的错误处理。

    def extract(request):
        respone = {'status': True, 'message': None, 'keyword': None, 'pdigest': None}
    
        try:
            input_psg = request.POST.get('input_passage')
            handle_method = request.POST.get('handle_method')
    
            word3 = wordRank.wordRank(input_psg, limit = 3)
            digest = sentenceRank.sentenceRank(input_psg, limit = 1)
    
            keyword, pdigest = "", ""
            for w in word3:
                keyword += w[1] + " "
            keyword = keyword[0 : len(keyword) - 1]
            for w in digest:
                pdigest += w[1] + " "
    
            respone['keyword'] = keyword
            respone['pdigest'] = pdigest
    
    
        except Exception as e:
            print(e)
            respone['status'] = False
            respone['message'] = '获取结果失败'
    
        result = json.dumps(respone, ensure_ascii=False)
        return HttpResponse(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

算法模块

算法模块涉及到的内容以及在“核心思想与算法描述”中介绍,将实现textrank所需要的各种数据集,数据结构和代码封装成一个包,并向外提供两个接口:

  • sentenceRank:摘要抽取接口,输入文章,输出指定个数摘要
  • wordRank:关键词抽取接口,输入文章,输出指定个数的关键词

将该算法工具包嵌入到django的框架中,通过后端响应模块的view函数进行调用,实现模块之间数据的传递

实验结果及分析

本作业通过ROUGE来对算法进行评测,ROUGE通过将自动生成的摘要与一组摘要(一般由人工生成)进行比较计算,得到相应的分数,依此来衡量自动生成的摘要与参考摘要之间的相似度。

ROUGE-N的定义为:
R O U G E − N = ∑ S ∈ r e f ∑ g r a m n ∈ S C o u n t m a t c h ( g r a m n ) ∑ S ∈ r e f ∑ g r a m n ∈ S C o u n t ( g r a m n ) ROUGE-N=\frac{\sum_{S\in ref}\sum_{gram_n\in S}Count_{match}(gram_n)}{\sum_{S\in ref}\sum_{gram_n\in S}Count(gram_n)} ROUGEN=SrefgramnSCount(gramn)SrefgramnSCountmatch(gramn)
其中分母为测试集中每个测试用例中 g r a m n gram_n gramn的个数总和,而分子为每个每个测试用例中共有的 g r a m n gram_n gramn的总和

本作业使用NLPCC2017的摘要数据(数据来源),选择前 200 200 200篇文章对textrank摘要抽取算法进行计算,计算其ROUGE-1得到的结果如下表所示:

PRF
ROUGE-1 0.05 0.05 0.05 0.1 0.1 0.1 0.06666666222222252 0.06666666222222252 0.06666666222222252

由于使用的是抽取式的计算方法,摘要为原文中的一句话,而无法生成摘要会导致准确率不高的情况出现,从实验结果中也可见准确率要低于召回率。

要解决此此问题,提高算法性能则需要考虑使用生成式的摘要方法,当前比较主流的有如transformer模型或者Seq2seq模型+注意力机制的算法。在本次作业原先的规划中,要实现一个transformer模型来完成摘要的生成,并对比摘要抽取和摘要生成之间的性能差异。但由于时间和小组成员较为有限,且对pytorch不够熟悉,没有能够完成预期的实现。

虽然没有完成预期的摘要生成模型,但我们会在接下来假期的时间里继续研究这个问题,进一步学习基于神经网络的摘要生成算法。本作业github仓库,将在作业提交截止后开放。

虽然使用抽取式的算法召回率并不高,但在实际使用中还是能够一定的效果:

随便选择一个当天的新闻进行摘要,结果如下:

而当“摘要生成”遇到“废话生成器”,结果如下:

参考资料

  • 测试数据集来源https://github.com/liucongg/GPT2-NewsTitle
  • 停用词表来源https://github.com/goto456/stopwords
  • 分词使用jieba库https://pypi.org/project/jieba/

资源下载地址:https://download.csdn.net/download/sheziqiong/85736065
资源下载地址:https://download.csdn.net/download/sheziqiong/85736065

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/281712
推荐阅读
相关标签
  

闽ICP备14008679号