PositionRank代码解读(四)

2021SC@SDUSC

Evaluation.py模块分析

Rprecision方法

def Rprecision(predicted, gold, k):

    hits = set(predicted).intersection(set(gold))
    Rpr = 0.0
    if len(hits)>0 and len(predicted)>0:
        Rpr =  len(hits)*1.0/k

    return Rpr

该方法用于计算精确率,精准率表示算法提取的关键词与人工给定关键词相匹配的个数与算法提取的总关键词数量的比值

使用预测到的结果集合和人工标注的关键词取交集(intersection()方法),然后用该集合的大小除以预测到的总数,得到精确率。

PRF方法

def PRF(predicted, gold, k):
    predicted = predicted[:k]
    # 获取交集
    hits = set(predicted).intersection(set(gold))
    # 初始化精确率、召回率、F1分数
    P, R, F1 = 0.0, 0.0, 0.0
    # 计算
    if len(hits)>0 and len(predicted)>0:
        P =  len(hits)/len(predicted)
        R = len(hits)/len(gold)
        F1 = 2*P*R/(P+R)

    return {
    
    'precision':P,'recall': R,'f1-score': F1}

该方法用于计算精确率、召回率、F1分数,关于精确率之前已经提到。召回率则表示算法提取的关键词与人工给定关键词相匹配的个数与人工给出的关键词数量的比值

F1分数表示精确率和召回率的调和平均数,当精准率和召回率两个指标发生冲突时,通常采用F1分数进行综合考量。F1分数的优点在于可以避免极大值对于结果的影响。

PRF_range方法

def PRF_range(predicted, gold, k):
    # 初始化结果列表
    P = []
    R = []
    F1 = []
    # 循环k次
    for i in range(0,k):
        predict = predicted[:i+1]
        # 取交集
        hits = set(predict).intersection(set(gold))
        # 初始化分数
        pr = 0.0
        re = 0.0
        f1 = 0.0
        if len(hits)>0 and len(predict)>0:
            pr =  len(hits)*1.0/len(predict)
            re = len(hits)*1.0/len(gold)
        if pr+re > 0:
            f1 = 2*pr*re/(pr+re)
        P.append(pr)
        R.append(re)
        F1.append(f1)

    return P,R,F1

该方法用于计算top1-topk的P、R、F1指标

计算方法和PRF方法一致,区别在于加入了一层0到k的for循环,返回结果列表。

Bpref方法

def Bpref (pred, gold):
    incorrect = 0
    correct = 0
    bpref = 0
    # 当错误集中在前面时该值会较小
    for kp in pred:
        if kp in gold:
            bpref += (1.0 - (incorrect*1.0/len(pred)))
            correct += 1
        else:
            incorrect +=1

    if correct >0:
        bpref = bpref*1.0/correct
    else:
        bpref = 0.0

    return bpref

在网上没有找到关于该指标的解释,这里说一下我对它的理解。该指标用于考虑算法对于关键词预测后的排名效果。召回率和精确率都只考虑了整体的效果,然而PositionRank的一个很重要的能力是为关键词打分,将最有可能成为关键词的结果排在前面,精确率和召回率都不能很好描述这一点(当然分别计算topk的精确率和召回率除外)。而该指标受到排名结果的影响,当正确结果数目一致,并且排名靠前时该指标数值较大。

_main_模块中对指标计算的控制

首先为候选词打分,同时得到排名结果(candidate_scoring已经分析过)

            # 为候选词打分、计算排名,核心算法,基于图的PageRank算法
            system.candidate_scoring(update_scoring_method=False)
            # 计算结果指标
            currentP, currentR, currentF1 = \
                evaluation.PRF_range(system.get_best_k(args.topK), gold_stemmed, k=args.topK)

使用PRF_range方法计算top1-topk的相关指标。

扫描二维码关注公众号,回复: 13562372 查看本文章

其中的get_best_k()方法如下:

    def get_best_k(self, k=10):
        """
        得到排名前k的候选词
        :param k: top keyphrases to be retuned
        :return: top k keyphrases and their weights
        """

        # 计算排名,使用weight作为指标,倒序返回(从大到小)
        sorted_weights = sorted(self.weights, key=self.weights.get, reverse=True)

        # 返回前k个结果
        return sorted_weights[:(min(k, len(sorted_weights)))]

对数据集中所有文档的相应结果进行累加

            P = map(sum, zip(P, currentP))
            R = map(sum, zip(R, currentR))
            F1 = map(sum, zip(F1, currentF1))

这种形式是第一次见到,zip(P,currentP)可以得到一个元组第一个元素是前(i-1)次累加得到的结果,第二个元素是本次计算得到的结果map(sum,)将二者加在 了一起,将结果赋值给了P。由于P和currentP都是长度为k的列表,这种方式极大的简化了代码。

之后对累加结果进行归一化处理并打印结果。

    # 归一化
    P = [p / docs for p in P]
    R = [r / docs for r in R]
    F1 = [f / docs for f in F1]
    
    print('Evaluation metrics:'.ljust(20, ' '), 'Precision @k'.ljust(20, ' '), 'Recall @k'.ljust(20, ' '),
          'F1-score @k')

    for i in range(0, args.topK):
        print(''.ljust(20, ' '),
              'Pr@{}'.format(i + 1).ljust(6, ' '), '{0:.3f}'.format(P[i]).ljust(13, ' '),
              'Re@{}'.format(i + 1).ljust(6, ' '), '{0:.3f}'.format(R[i]).ljust(13, ' '),
              'F1@{}'.format(i + 1).ljust(6, ' '), '{0:.3f}'.format(F1[i]))

猜你喜欢

转载自blog.csdn.net/Simonsdu/article/details/121884973