zoukankan      html  css  js  c++  java
  • 关键词提取算法TextRank

    很久以前,我用过TFIDF做过行业关键词提取。TFIDF仅仅从词的统计信息出发,而没有充分考虑词之间的语义信息。现在本文将介绍一种考虑了相邻词的语义关系、基于图排序的关键词提取算法TextRank。

    1. 介绍

    TextRank由Mihalcea与Tarau于EMNLP'04 [1]提出来,其思想非常简单:通过词之间的相邻关系构建网络,然后用PageRank迭代计算每个节点的rank值,排序rank值即可得到关键词。PageRank本来是用来解决网页排名的问题,网页之间的链接关系即为图的边,迭代计算公式如下:

    [PR(V_i) = (1-d) + d * sum_{j in In(V_i)} frac{1}{|Out(V_j)|}PR(V_j) ]

    其中,(PR(V_i))表示结点(V_i)的rank值,(In(V_i))表示结点(V_i)的前驱结点集合,(Out(V_j))表示结点(V_j)的后继结点集合,(d)为damping factor用于做平滑。

    网页之间的链接关系可以用图表示,那么怎么把一个句子(可以看作词的序列)构建成图呢?TextRank将某一个词与其前面的N个词、以及后面的N个词均具有图相邻关系(类似于N-gram语法模型)。具体实现:设置一个长度为N的滑动窗口,所有在这个窗口之内的词都视作词结点的相邻结点;则TextRank构建的词图为无向图。下图给出了由一个文档构建的词图(去掉了停用词并按词性做了筛选):

    考虑到不同词对可能有不同的共现(co-occurrence),TextRank将共现作为无向图边的权值。那么,TextRank的迭代计算公式如下:

    [WS(V_i) = (1-d) + d * sum_{j in In(V_i)} frac{w_{ji}}{sum_{V_k in Out(V_j)} w_{jk}} WS(V_j) ]

    2. 评估

    接下来将评估TextRank在关键词提取任务上的准确率、召回率与F1-Measure,并与TFIDF做对比;准确率计算公式如下:

    [Precision = frac{1}{N} sum_{i=0}^{N-1} frac{left|P_i cap T_i ight|}{left|P_i ight|} ]

    其中,(N)为文档数量,(P_i)为文档(i)所提取出的关键词,(T_i)为文档的标注关键词。召回率与F1的计算公式如下:

    [Recall = frac{1}{N} sum_{i=0}^{N-1} frac{left|P_i cap T_i ight|}{left|T_i ight|} ]

    [F1 = frac{2*Precision*Recall}{Precision + Recall} ]

    测试集是由刘知远老师提供的网易新闻标注数据集,共有13702篇文档。Jieba完整地实现了关键词提取TFIDF与TextRank算法,基于Jieba-0.39的评估实验代码如下:

    import jieba.analyse
    import json
    import codecs
    
    
    def precision_recall_fscore_support(y_true, y_pred):
        """
        evaluate macro precision, recall and f1-score.
        """
        doc_num = len(y_true)
        p_macro = 0.0
        r_macro = 0.0
        for i in range(doc_num):
            tp = 0
            true_len = len(y_true[i])
            pred_len = len(y_pred[i])
            for w in y_pred[i]:
                if w in y_true[i]:
                    tp += 1
            p = 1.0 if pred_len == 0 else tp / pred_len
            r = 1.0 if true_len == 0 else tp / true_len
            p_macro += p
            r_macro += r
        p_macro /= doc_num
        r_macro /= doc_num
        return p_macro, r_macro, 2 * p_macro * r_macro / (p_macro + r_macro)
    
    
    file_path = 'data/163_chinese_news_dataset_2011.dat'
    with codecs.open(file_path, 'r', 'utf-8') as fr:
        y_true = []
        y_pred = []
        for line in fr.readlines():
            d = json.loads(line)
            content = d['content']
            true_key_words = [w for w in set(d['tags'])]
            y_true.append(true_key_words)
            # for w in true_key_words:
            #     jieba.add_word(w)
            key_word_pos = ['x', 'ns', 'n', 'vn', 'v', 'l', 'j', 'nr', 'nrt', 'nt', 'nz', 'nrfg', 'm', 'i', 'an', 'f', 't',
                            'b', 'a', 'd', 'q', 's', 'z']
            extract_key_words = jieba.analyse.extract_tags(content, topK=2, allowPOS=key_word_pos)
            # trank = jieba.analyse.TextRank()
            # trank.span = 5
            # extract_key_words = trank.textrank(content, topK=2, allowPOS=key_word_pos)
            y_pred.append(extract_key_words)
        prf = precision_recall_fscore_support(y_true, y_pred)
        print('precision: {}'.format(prf[0]))
        print('recall: {}'.format(prf[1]))
        print('F1: {}'.format(prf[2]))
    

    其中,每个文档提取的关键词数为2,并按词性做过滤;span表示TextRank算法中的滑动窗口的大小。评估结果如下:

    方法 Precision Recall F1-Measure
    TFIDF 0.2697 0.2256 0.2457
    TextRank span=5 0.2608 0.2150 0.2357
    TextRank span=7 0.2614 0.2155 0.2363

    如果将标注关键词添加到自定义词典,则评估结果如下:

    方法 Precision Recall F1-Measure
    TFIDF 0.3145 0.2713 0.2913
    TextRank span=5 0.2887 0.2442 0.2646
    TextRank span=7 0.2903 0.2455 0.2660

    直观感受下关键词提取结果(添加了自定义词典):

    // TFIDF, TextRank, labelled
    ['文强', '陈洪刚'] ['文强', '陈洪刚'] {'文强', '重庆'}
    ['内贾德', '伊朗'] ['伊朗', '内贾德'] {'制裁', '世博', '伊朗'}
    ['调控', '王珏林'] ['调控', '楼市'] {'楼市', '调控'}
    ['罗平县', '男子'] ['男子', '罗平县'] {'被砍', '副局长', '情感纠葛'}
    ['佟某', '黄玉'] ['佟某', '黄现忠'] {'盲井', '伪造矿难'}
    ['女生', '聚众淫乱'] ['女生', '聚众淫乱'] {'聚众淫乱', '东莞', '不雅视频'}
    ['马英九', '和平协议'] ['马英九', '推进'] {'国台办', '马英九', '和平协议'}
    ['东帝汶', '巡逻艇'] ['东帝汶', '中国'] {'东帝汶', '军舰', '澳大利亚'}
    ['墨西哥', '警方'] ['墨西哥', '袭击'] {'枪手', '墨西哥', '打死'}
    

    从上述两组实验结果,可以发现:

    • TextRank与TFIDF均严重依赖于分词结果——如果某词在分词时被切分成了两个词,那么在做关键词提取时无法将两个词黏合在一起(TextRank有部分黏合效果,但需要这两个词均为关键词)。因此是否添加标注关键词进自定义词典,将会造成准确率、召回率大相径庭。
    • TextRank的效果并不优于TFIDF。
    • TextRank虽然考虑到了词之间的关系,但是仍然倾向于将频繁词作为关键词。

    此外,由于TextRank涉及到构建词图及迭代计算,所以提取速度较慢。

    3. 参考资料

    [1] Rada, Mihalcea, and Paul Tarau. "TextRank: Bringing Order into Texts." empirical methods in natural language processing (2004): 404-411.

  • 相关阅读:
    leetcode 78. 子集 JAVA
    leetcode 91. 解码方法 JAVA
    leetcode 75. 颜色分类 JAVA
    leetcode 74 搜索二维矩阵 java
    leetcode 84. 柱状图中最大的矩形 JAVA
    last occurance
    first occurance
    classical binary search
    LC.234.Palindrome Linked List
    LC.142. Linked List Cycle II
  • 原文地址:https://www.cnblogs.com/en-heng/p/6626210.html
Copyright © 2011-2022 走看看