TextRank算法主要用来生成文本的关键词和摘要,其来源于PageRank算法,下面先介绍PageRank。PageRank在搜索领域有广泛的应用,最开始用来计算网页的重要性。可以把整个网络看成有向图,网页是结点,如果网页A中存在一条链接指向网页B,则认为A到B存在一条有向边。


    S(Vi)表示网页i的重要性即PR值,d是阻尼系数(确保当一个网页没有链接指向它时,也有一定PR值),经验一般设置为0.85,In(Vi)是包含指向网页i的链接的网页集合。Out(Vj)是网页j中指向其他网页的链接的集合,S(Vj)代表网页j的PR值。所以对于一个网页,它的重要性取决于到它的每个链接页面的重要性之和,每个链接到该网页的页面的PR值S(Vj)同时还需要对其他的页面贡献评分,所以除以了|Out(Vj)|。另外,网页的重要性不单单由链接网页决定,还包含一定的概率要不要接受其他网页的重要性评价,这也就是d的作用。
    初始时,可以将各个网页的重要性值设置为1,PageRank经过多次迭代最终得到结果。公式左边代表迭代后的网页PR值,等号右边的是迭代前的PR值。

TextRank提取关键词:


    该公式跟PageRank基本相似,其中多了一个重要参数Wji,用来代表两个节点间的重要程度。算法流程如下:将给定的文本分割成句子,T=[S1,S2,......,Sm],然后对每个句子进行分词,得到Si=[pi1,pi2,...,pin],构建词图。设定窗口大小为k,[p1,p2,...,pk][p2,p3,...,pk+1]等都是一个个的窗口,在一个窗口中如果两个单词同时出现,则认为对应单词节点间存在一个边。根据这个思想和公式迭代传播词图中的各节点权重,直至收敛。最后对节点权重进行排序,从而得到最重要的几个单词作为候选关键词。若提取出来的若干关键词在文本中相邻,则构成一个关键短语。

TextRank生成摘要:



    将文本中的每个句子看做一个节点,如果两个句子有相似性,则认为两个句子对应的节点之间存在一条无向有权边。句子相似度的计算式子如上所示,Si、Sj两个句子,Wk代表句子中的单词,那么分子代表同时出现在两个句子中的单词的个数,分母是对句子中单词个数求对数之和。分母使用对数可以抵消长句子在相似度计算上的优势(长句子包含相同单词的可能性更高)。根据以上相似度公式循环迭代计算得到任意两个节点之间的相似度,构建节点连接图,最后计算PR值,经排序选出PR值最高的的节点对应的句子作为摘要。

def solve(self): #针对抽关键句
        for cnt, doc in enumerate(self.docs):
            scores = self.bm25.simall(doc) #在本实现中,使用的不是前面提到的公式,而是使用的BM25算法,之前会有一个预处理(self.bm25 = BM25(docs)),然后求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 solve(self):#针对抽关键词
        for doc in self.docs:
            que = []
            for word in doc:
                if word not in self.words:
                    self.words[word] = set()
                    self.vertex[word] = 1.0
                que.append(word)
                if len(que) > 5:
                    que.pop(0)
                for w1 in que:
                    for w2 in que:
                        if w1 == w2:
                            continue
                        self.words[w1].add(w2)
                        self.words[w2].add(w1)
        for _ in range(self.max_iter):
            m = {}
            max_diff = 0
            tmp = filter(lambda x: len(self.words[x[0]]) > 0,
                         self.vertex.items())
            tmp = sorted(tmp, key=lambda x: x[1] / len(self.words[x[0]]))
            for k, v in tmp:
                for j in self.words[k]:
                    if k == j:
                        continue
                    if j not in m:
                        m[j] = 1 - self.d
                    m[j] += (self.d / len(self.words[k]) * self.vertex[k]) #利用之前提到的公式,简化的结果。
            for k in self.vertex:
                if k in m and k in self.vertex:
                    if abs(m[k] - self.vertex[k]) > max_diff:
                        max_diff = abs(m[k] - self.vertex[k])
            self.vertex = m
            if max_diff <= self.min_diff:
                break
        self.top = list(self.vertex.items())
        self.top = sorted(self.top, key=lambda x: x[1], reverse=True)

参考资料:https://blog.csdn.net/kamendula/article/details/51756552

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐