ITS·黑客

【小实验】“关键字”法完成新闻摘要提取

2017-05-14  本文已影响34人  某米狼

完成一个相对简单的“关键字提取”算法
思路:拥有关键词最多的句子就是最重要的句子。我们把句子按照关键词数量的多少排序,取前n句,即可汇总成我们的摘要。

步骤:

  1. 给在文章中出现的单词按照算法计算出重要性
  2. 按照句子中单词的重要性算出句子的总分
  3. 按照句子的总分给文章中的每个句子排序
  4. 取出前n个句子作为摘要
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 是一个列表,包含了英文中那些频繁出现的词,如am, is, are。
defaultdict 是一个带有默认值的字典容器。
puctuation 是一个列表,包含了英文中的标点和符号。
nlargest() 函数可以很快地求出一个容器中最大的n个数字。
"""

stopwords = set(stopwords.words('english') + list(punctuation))
#stopwords包含的是我们在日常生活中会遇到的出现频率很高的词,如do, I, am, is, are等等,这种词汇是不应该算是我们的 关键字。同样的标点符号(punctuation)也不能被算作是关键字。

max_cut = 0.9
min_cut = 0.1
#限制了在文本中出现重要性过高过低的词。就像在跳水比赛中会去掉最高分和最低分一样。我们也需要去掉那些重 要性过高和过低的词来提升算法的效果。


def compute_frequencies(word_sent):
    """
    计算出每个词出现的频率
    :param word_sent: 是一个已经分好词的列表
    :return: 一个词典freq[], freq[w]代表了w出现的频率
    """
    freq = defaultdict(int)#defaultdict和普通的dict 的区别是它可以设置default值 参数是int默认值是0
    #统计每个词出现的频率:
    for s in word_sent:
        for word in s:
            if word not in stopwords:
                freq[word] += 1
    #得出最高出现频次m            
    m = float(max(freq.values()))
    #所有单词的频次统除m
    for w in list(freq.keys()):
        freq[w] = freq[w]/m
        if freq[w] >= max_cut or freq[w] <= min_cut:
            del freq[w]
    # 最后返回的是
    # {key:单词, value: 重要性}
    return freq

def summarize(text, n):
    """
    用来总结的主要函数
    text是输入的文本 
    n是摘要的句子个数 
    返回包含摘要的列表
    """

    # 首先先把句子分出来
    sents = sent_tokenize(text)
    assert n <= len(sents)

    # 然后再分词
    word_sent = [word_tokenize(s.lower()) for s in sents]
    # self._freq是一个词和词频率的字典
    freq = compute_frequencies(word_sent)
    #ranking则是句子和句子重要性的词典
    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]

"""
考虑到句子比较多的情况 
用遍历的方式找最大的n个数比较慢 
我们这里调用heapq中的函数 
创建一个最小堆来完成这个功能 
返回的是最小的n个数所在的位置 
"""
def rank(ranking, n):
    return nlargest(n, ranking, key=ranking.get)

#运行程序
if __name__ == '__main__':
    with open("news.txt", "r") as myfile:
        text = myfile.read().replace('\n','')
    res = summarize(text, 2)
    for i in range(len(res)):
        print("* " + res[i])

分析这篇文章:脸书推出人工智能翻译,谷歌感到压力山大
得到:

疑问:

n=2 为什么这么两大段,不应该是两个句子吗?

上一篇下一篇

猜你喜欢

热点阅读