NLP分类效果衡量指标(F1/p/r)

概念

为什么要计算F1:避免样本分布带来的偏差,综合考量分类效果,假如有100个样本,其中1个正样本,99个负样本,如果模型的预测只输出0,那么正确率是99%,这时候用正确率来衡量模型的好坏显然是不对的。

真实 1真实 0
预测 1True Positive(TP)False Positive(FP)
预测 0False Negative(FN)True Negative(TN)
  • 查准率(precision),预测正确的样本在所有预测为1的样本中的比例,该值反映有多少其他类被错误的归为该类。
  • 召回率(recall),预测正确的样本在所有真实为1的样本中的比例,该值反映有多少该类被预测为其他类了。
  • F1(F1-Score), 精准率和召回率的调和平均数。

Micro-F1与Macro-F1

针对多标签分类而言衡量分类效果

  • Micro-F1:直接计算所有类别的Precision和Recall,然后计算F1。(类别有权重,分到样本数多的类别有更大的影响力)
  • Macro-F1:计算出每一个类的Precision和Recall并分别计算F1,最后将F1平均。(各类别的F1权重相同)

代码实现

二分类

def f1(y_hat, y_true):
    '''
    输入张量y_hat是输出层经过sigmoid激活的张量
    y_true是label{0,1}的集和
    model指的是如果是多任务分类,single会返回每个分类的f1分数,multi会返回所有类的平均f1分数(Marco-F1)
    如果只是单个二分类任务,则可以忽略model
    '''
    epsilon = 1e-7
    y_hat = tf.round(y_hat)#将经过sigmoid激活的张量四舍五入变为0,1输出
    
    #  输入的数据是矩阵,标签为单行矩阵,预测值为单列矩阵,如果不是需要转换
     
    tp = tf.cast(tf.matmul(y_true,y_hat), 'float')
    #tn = tf.sum(tf.cast((1-y_hat)<em>(1-y_true), 'float'), axis=0)
    fp = tf.cast(tf.matmul(1-y_true,y_hat), 'float')
    fn = tf.cast(tf.matmul(y_true,1-y_hat), 'float')
    print('tp: ', tp[0][0].numpy(),'fp: ',  fp[0][0].numpy(),'fn: ',  fn[0][0].numpy())
    p = tp/(tp+fp+epsilon)#epsilon的意义在于防止分母为0,否则当分母为0时python会报错
    r = tp/(tp+fn+epsilon)

    f1 = 2</em>p<em>r/(p+r+epsilon)
   
    result = [f1[0][0].numpy(), p[0][0].numpy(), r[0][0].numpy()]
    return result

多标签

import tensorflow as tf
def f1(y_hat, y_true, model='multi'):
    '''
    输入张量y_hat是输出层经过sigmoid激活的张量
    y_true是label{0,1}的集和
    model指的是如果是多任务分类,single会返回每个分类的f1分数,multi会返回所有类的平均f1分数(Marco-F1)
    如果只是单个二分类任务,则可以忽略model
    '''
    epsilon = 1e-7
    y_hat = tf.round(y_hat)#将经过sigmoid激活的张量四舍五入变为0,1输出
 
    #tf.cast()转换张量数据类型
    tp = tf.reduce_sum(tf.cast(y_hat</em>y_true, 'float'), axis=0) #取axis维数据求和
    #tn = tf.sum(tf.cast((1-y_hat)<em>(1-y_true), 'float'), axis=0)
    fp = tf.reduce_sum(tf.cast((1-y_hat)</em>y_true, 'float'), axis=0)
    fn = tf.reduce_sum(tf.cast(y_hat<em>(1-y_true), 'float'), axis=0)

    p = tp/(tp+fp+epsilon)#epsilon的意义在于防止分母为0,否则当分母为0时python会报错
    r = tp/(tp+fn+epsilon)

    f1 = 2</em>p*r/(p+r+epsilon)
    f1 = tf.where(tf.is_nan(f1), tf.zeros_like(f1), f1)
    if model == 'single':
        return f1
    if model == 'multi':
        return tf.reduce_mean(f1)

参考

https://blog.csdn.net/zjn295771349/article/details/84961596

https://blog.csdn.net/lyb3b3b/article/details/84819931

https://www.jianshu.com/p/30b40b504bae

Leave a Reply