摘要抽取算法——最大边界相关算法MMR(Maximal Marginal Relevance)

用途

快速的抽取出一篇文章的主要内容,这样读者就能够通过最少的文字,了解到文章最要想表达的内容

方法

一种是生成式:生成式一般采用的是监督式学习算法,最常见的就是seq2seq模型,需要大量的训练数据。

生成式的优点是模型可以学会自己总结文章的内容,而它的缺点是生成的摘要可能会出现语句不通顺的情况。

另一种是抽取式:常见的算法是 textrank,MMR(Maximal Marginal Relevance),当然也可以采用深度学习算法。

抽取式指的摘要是从文章中抽出一些重要的句子,代表整篇文章的内容。

抽取式的优点是生成的摘要不会出现语句不通顺的情况,而它的缺点是缺乏文本总结能力,生成的摘要可能出现信息丢失的情况。

摘要抽取算法——最大边界相关算法MMR(Maximal Marginal Relevance)_第1张图片

MMR摘要抽取算法python实现

# coding=utf-8
from gensim.models import word2vec
import jieba.analyse
import json
from collections import Counter
import time
from scipy.linalg import norm
import warnings
from nlg_yongzhuo.data_preprocess.text_preprocess import jieba_cut, tfidf_fit
from nlg_yongzhuo.data.stop_words.stop_words import stop_words
import copy
from ltp import LTP

ltp = LTP()  # 默认加载 Small 模型
warnings.filterwarnings('ignore')


class Auto_Abstract(object):
    def __init__(self):
        self.stop_words = stop_words.values()
        self.algorithm = 'mmr'

    def cut_sentence(self, sentence):
        """
            分句
        :param sentence:str
        :return:list
        """
        re_sen = re.compile('[:;!?。:;?!\n\r]')  # .不加是因为不确定.是小数还是英文句号(中文省略号......)
        sentences = re_sen.split(sentence)
        sen_cuts = []
        for sen in sentences:
            # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
            if sen and str(sen).strip():
                sen_cuts.append(sen)
        return sen_cuts

    def extract_chinese(self, text):
        """
          只提取出中文、字母和数字
        :param text: str, input of sentence
        :return:
        """
        text = re.sub(r' ', '', text)
        chinese_exttract = ''.join(re.findall(u"([\u4e00-\u9fa5A-Za-z0-9@. ])", text))
        return chinese_exttract

    def extract_keywords(self, text):  # 根据词频返回关键字
        words_counter = Counter()
        for line in jieba.cut(text):
            if line not in self.stop_words:
                words_counter[line] += 1
        keywords = list(map(lambda x: x[0], words_counter.most_common()[:20]))
        counts = list(map(lambda x: x[1], words_counter.most_common()[:20]))
        return keywords, counts

    def summarize(self, text, num=2, alpha=0.6):
        """
        :param text: str
        :param num: int
        :return: list
        """
        # 切句
        cal_text = self.extract_chinese(text)
        self.sentences = ltp.sent_split([text])
        for i in self.sentences:
            if len(i) < 15:
                self.sentences.remove(i)
        # 切词
        sentences_cut = [[word for word in jieba_cut(self.extract_chinese(sentence))
                          if word.strip()] for sentence in self.sentences]
        # 去除停用词等
        self.sentences_cut = [list(filter(lambda x: x not in self.stop_words, sc)) for sc in sentences_cut]
        self.sentences_cut = [" ".join(sc) for sc in self.sentences_cut]
        # 计算每个句子的词语个数
        # sen_word_len = [len(sc)+1 for sc in sentences_cut]
        # 计算每个句子的tfidf
        sen_tfidf = tfidf_fit(self.sentences_cut)
        # 矩阵中两两句子相似度
        SimMatrix = (sen_tfidf * sen_tfidf.T).A  # 例如: SimMatrix[1, 3]  # "第2篇与第4篇的相似度"
        # 输入文本句子长度
        len_sen = len(self.sentences)
        # 句子标号
        sen_idx = [i for i in range(len_sen)]
        summary_set = []
        mmr = {
     }
        for i in range(len_sen):
            if not self.sentences[i] in summary_set:
                sen_idx_pop = copy.deepcopy(sen_idx)
                sen_idx_pop.pop(i)
                # 两两句子相似度
                sim_i_j = [SimMatrix[i, j] for j in sen_idx_pop]
                score_tfidf = sen_tfidf[i].toarray()[0].sum()  # / sen_word_len[i], 如果除以词语个数就不准确
                mmr[self.sentences[i]] = alpha * score_tfidf - (1 - alpha) * max(sim_i_j)
                summary_set.append(self.sentences[i])
        score_sen = [rc[0] for rc in sorted(mmr.items(), key=lambda d: d[1], reverse=True)]
        if len(mmr) > num:
            score_sen = score_sen[0:num]
        keywords, counts = self.extract_keywords(cal_text)
        return "".join(score_sen)

    def predict_txt(self, file_path):  # 读取一个txt文件
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                text = f.read()
        except:
            with open(file_path, 'r', encoding='gbk') as f:
                text = f.read()
        result, keywords, counts = self.summarize(text)

        return result


if __name__ == '__main__':
    # starttime = time.time()
    aa = Auto_Abstract()
    result = aa.summarize("""近年来,随着计算机技术的迅速发展,人脸自动识别技术得到广泛研究与开发,人脸识别成为近 30 年里模式识别和图像处理中最热门的研究主
题之一。人脸识别的目的是从人脸图像中抽取人的个性化特征,并以此
来识别人的身份。一个简单的自动人脸识别系统,包括以下 4 个方面的
内容 :
    (1) 人脸检测 (Detection) :即从各种不同的场景中检测出人脸的存在
并确定其位置。
    (2) 人脸规范化 (Normalization) :校正人脸在尺度、光照和旋转等方
面的变化。或者叫做 alignment ,人脸对齐,人脸校准
    (3) 人脸校验 (Face verification ) :采取某种方式表示检测出人脸和
数据库中的已知人脸,确认两张脸是否是同一个人。
    (4) 人脸识别 (Recognition) :将待识别的人脸与数据库中的已知人脸
比较,得出给你的脸是库里的谁。
""")
    # endtime = time.time()
#     print(endtime - starttime)
    print(result)

近年来,随着计算机技术的迅速发展,人脸自动识别技术得到广泛研究与开发,人脸识别成为近 30 年里模式识别和图像处理中最热门的研究主(3) 人脸校验 (Face verification ) :采取某种方式表示检测出人脸和

这种算法起码能用下,其余的一些输出太不规则了,很难商用化,但是有个缺点,就是当一句话从中间切开时无法拼接起来,主要是原始文档有误,这个之后再想办法,以及优化

参考

https://www.jianshu.com/p/4a2f7e5d45da
https://github.com/yongzhuo/nlg-yongzhuo

你可能感兴趣的:(日常问题,算法,MMR,摘要抽取,NLP)