nlk学习笔记 新闻摘要自动提取

一、关键字

1.项目概述

主要完成一个相对简单的 “关键字提取” 算法,可以提取英文新闻中关键的消息

2.项目构思

拥有关键词最多的句子就是最重要的句子。我们把句子按照关键词数量的多少排序,取前 n 句,即可汇总成我们的摘要。

所以我们的工作可以分为如下步骤:

  • 给在文章中出现的单词按照算法计算出重要性
  • 按照句子中单词的重要性算出句子的总分
  • 按照句子的总分给文章中的每个句子排序
  • 取出前 n 个句子作为摘要

3.项目技术栈

from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords
from collections import defaultdict
from string import punctuation
from heapq import nlargest

nltk.tokenize 是 NLTK 提供的分词工具包。所谓的分词 tokenize 实际就是把段落分成句子,把句子分成一个个单词的过程。我们导入的 sent_tokenize() 函数对应的是分段为句。 word_tokenize() 函数对应的是分句为词。

stopwords 是一个列表,包含了英文中那些频繁出现的词,如 amisare

defaultdict 是一个带有默认值的字典容器。

puctuation 是一个列表,包含了英文中的标点和符号。

nlargest() 函数可以很快地求出一个容器中最大的 n 个数字。

 4.实现思路

词频统计

首先我们先要统计出每个词在文章中出现的次数,在统计出次数之后,我们可以知道出现次数最多的词的出现次数 m 。

我们把每个词 wi 出现的次数 mi 除以 m ,算出每个词的 “重要系数”。

重要性高的词就是我们的关键词。

def compute_frequencies(word_sent):
    freq = defaultdict(int)
    for s in word_sent:
        for word in s:
            if word not in stopwords:
                freq[word] += 1
    m = float(max(freq.values()))
    for w in list(freq.keys()):
        freq[w] = freq[w]/m
        if freq[w] >= max_cut or freq[w] <= min_cut:
            del freq[w]
    return freq

获得摘要

现在每个单词(stopwords 和出现频率异常的单词除外)都有了 “重要性” 这样一个量化描述的值。我们现在需要统计的是一个句子中单词的重要性。只需要把句子中每个单词的重要性叠加就行了。

def summarize(text, n):
    sents = sent_tokenize(text)
    assert n <= len(sents)
    word_sent = [word_tokenize(s.lower()) for s in sents]
    freq = compute_frequencies(word_sent)
    ranking = defaultdict(int)
    for i, word in enumerate(word_sent):
        for w in word:
            if w in freq:
                ranking[i] += freq[w]
    sents_idx = rank(ranking, n)
    return [sents[j] for j in sents_idx]

 二、TextRank 算法

1.项目概述及项目构思

PageRank 算法

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

于是我们就可以列出一张邻接矩阵来描述推荐出去 (Out) 的箭头,别的界面推荐进来 (In) 的箭头。形成一个邻接矩阵。每一代表的是你推荐的页面 (Out) 。如 A 列,代表的就是 A 推荐的页面。如表格所描述的,A 谁也没有推荐。每一代表的是谁推荐了你 (In)。如 A 行,代表的就是推荐 A 的页面。如表格所描述的,D 推荐了 A。有了这张邻接矩阵作为基础,我们就能够计算 PageRank 的核心:每一个页面的分数 S

                                        𝑆(𝑉𝑖)=(1−𝑑)+𝑑∗∑𝑗∈In(𝑉𝑖)1lout(𝑉𝑗)|𝑆(𝑉𝑗)

我们会发现,每一个页面的分数 𝑆(𝑉𝑖)都是依赖于别的页面的分数 𝑆(𝑉𝑗)的。我们需要对每个页面的分数进行初始化。

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

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

                         𝑆𝑖𝑚𝑖𝑙𝑎𝑟𝑖𝑡𝑦(𝑆𝑖,𝑆𝑗)=||{𝑤𝑘|𝑤𝑘∈𝑆𝑖&𝑤𝑘∈𝑆𝑗}||log(|𝑆𝑖|)+log(||𝑆𝑗||)

相当于是在求两个句子之间的相似度,也就是推荐程度。根据推荐程度便可以列出一张邻接矩阵。

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

                        𝑊𝑆(𝑉𝑖)=(1−𝑑)+𝑑∗∑𝑉𝑗∈In(𝑉𝑖)𝑤𝑗𝑖∑𝑉𝑘∈𝑂𝑢𝑡(𝑉𝑗)𝑤𝑗𝑘𝑊𝑆(𝑉𝑗)

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

3.项目技术栈

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

4.思路

计算相似性

def calculate_similarity(sen1, sen2): 
    counter = 0
    for word in sen1: 
        if word in sen2: 
            counter += 1
    return counter / (math.log(len(sen1)) + math.log(len(sen2)))

创建相似度邻接矩阵

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

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

def weighted_pagerank(weight_graph): 
    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

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

 找出分数最高的两个句子

def Summarize(text,n):
    sents = sent_tokenize(text)
    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]

 

 

 

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值