【自然语言处理】基于TextRank算法的文本摘要

基于TextRank算法的文本摘要

文本摘要是自然语言处理(NLP)的应用之一,一定会对我们的生活产生巨大影响。随着数字媒体的发展和出版业的不断增长,谁还会有时间完整地浏览整篇文章、文档、书籍来决定它们是否有用呢?

利用计算机将大量的文本进行处理,产生简洁、精炼内容的过程就是文本摘要,人们可通过阅读摘要来把握文本主要内容,这不仅大大节省时间,更提高阅读效率。但人工摘要耗时又耗力,已不能满足日益增长的信息需求,因此借助计算机进行文本处理的自动文摘应运而生。

这类任务到目前为止主要分为两类:

  • 抽取式摘要:这种方法依赖于从文本中提取几个部分,例如短语、句子,把它们堆叠起来创建摘要。因此,这种抽取型的方法最重要的是识别出适合总结文本的句子。
  • 生成式摘要:通过建立抽象的语意表示,使用自然语言生成技术,形成摘要。可能总结中的文本甚至没有在原文中出现。

目前主要方法有:

  • 基于统计: 统计词频,位置等信息,计算句子权值,再选取权值高的句子作为文摘。简单易用,但对词句的使用大多仅停留在表面信息。
  • 基于图模型: 构建拓扑结构图,对词句进行排序。例如,TextRank、LexRank 等。
  • 基于潜在语义: 使用主题模型,挖掘词句隐藏信息。例如,LDA、HMM 等。
  • 基于整数规划: 将文摘问题转为整数线性规划,求全局最优解。

TextRank 是一种从 PageRank 发展而来的抽取型摘要算法。关于 PageRank 的介绍可以查看 我的这篇博客

基于 TextRank 的摘要算法在 PageRank 的基础上,用句子代替网页,把每个句子分别看做一个节点,如果两个句子有相似性,那么认为这两个句子对应的节点之间存在一条无向有权边,而句子的相似性方法是根据如下公式:

S i m i l a r i t y ( S i , S j ) = ∣ w k ∣ w k ∈ S i ∩ w k ∈ S j ∣ l o g ( ∣ S i ∣ ) + l o g ( ∣ S j ∣ ) Similarity(S_i,S_j)=\frac{|w_k|w_k\in S_i\cap w_k\in S_j|}{log(|S_i|)+log(|S_j|)} Similarity(Si,Sj)=log(Si)+log(Sj)wkwkSiwkSj

其中 S i S_i Si S j ​ S_j​ Sj 分别表示两个句子, w k ​ w_k​ wk 表示句子中的词,那么分子部分的意思是同时出现在两个句子中的同一个词的个数,分母是对句子中词的个数求对数和。分母这样的设计可以抑制较长的句子在相似度计算上的优势。不过通常在构造完句子词向量之后用余弦相似度就可以计算。

其主要的流程如下图。

在这里插入图片描述

  • 首先把文章合成文本数据。
  • 把文本分割成单个句子。
  • 为每个句子找到词向量表示。
  • 计算句子向量间的相似性。
  • 将相似性矩阵转换为以句子为节点,相似性得分为边的图结构,用于句子 TextRank 计算。
  • 最后一定数量的排名最高的句子构成最后的摘要。

SnowNLP 中的 文本摘要 使用的即是 TextRank 算法,源码如下所示。

from __future__ import unicode_literals

from ..sim.bm25 import BM25

class TextRank(object):

    def __init__(self, docs):
        self.docs = docs
        self.bm25 = BM25(docs)
        self.D = len(docs)
        self.d = 0.85
        self.weight = []
        self.weight_sum = []
        self.vertex = []
        self.max_iter = 200
        self.min_diff = 0.001
        self.top = []

    def solve(self):
        for cnt, doc in enumerate(self.docs):
            scores = self.bm25.simall(doc)
            self.weight.append(scores)
            self.weight_sum.append(sum(scores)-scores[cnt])
            self.vertex.append(1.0)
        for _ in range(self.max_iter):
            m = []
            max_diff = 0
            for i in range(self.D):
                m.append(1-self.d)
                for j in range(self.D):
                    if j == i or self.weight_sum[j] == 0:
                        continue
                    m[-1] += (self.d*self.weight[j][i]
                              / self.weight_sum[j]*self.vertex[j])
                if abs(m[-1] - self.vertex[i]) > max_diff:
                    max_diff = abs(m[-1] - self.vertex[i])
            self.vertex = m
            if max_diff <= self.min_diff:
                break
        self.top = list(enumerate(self.vertex))
        self.top = sorted(self.top, key=lambda x: x[1], reverse=True)

    def top_index(self, limit):
        return list(map(lambda x: x[0], self.top))[:limit]

    def top(self, limit):
        return list(map(lambda x: self.docs[x[0]], self.top))
from . import normal
from . import seg
from .summary import textrank

class SnowNLP(object):

    def __init__(self, doc):
        self.doc = doc
    
    ......

    def summary(self, limit=5):
	    doc = []
	    sents = self.sentences
	    for sent in sents:
	        words = seg.seg(sent)
	        words = normal.filter_stop(words)
	        doc.append(words)
	    rank = textrank.TextRank(doc)
	    rank.solve()
	    ret = []
	    for index in rank.top_index(limit):
	        ret.append(sents[index])
	    return ret
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

G皮T

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值