模型评估之“鱼网捞鱼”
整理文档时找到了模型评估的学习笔记,当时在群里跟朋友们聊到了模型评估时,用“池塘捞鱼”做了一个例子,整理出来,温故知新。
问题描述
如下图所示,在一个池塘里(矩形)有很多的鱼(三角形)和虾(棱形), 现在有一个模型,也就是一个用来捞鱼的网(圆形虚线),一网下去捞中了一些鱼,同时也捞中了一些虾。现在要对这个鱼网(模型)进行评价一下,鱼网做得好不好呢?
现在来分析一下:
池塘:总共的大小是20,其中鱼P=10, 虾N=10
模型就是一张网下去,捞了9个鱼和3个虾。(注意,网里的都是“被认为是鱼”的才被捞上来。)
捞到的网里正确的是鱼的:TP=9,
捞到的网里是虾被误认为是鱼的: FP=3
网的大小:P’ = 9+3=12
现在注意了:池塘里那些没有被网上来的,就是认为全是虾。这一部分叫N’
下面做一个表格来表示一下:
认为是鱼的(鱼网) | 认为是虾(鱼网外) | 小计 | |
---|---|---|---|
真正是鱼 | TP=9 | FN=1 | P=10 |
真正是虾 | FP=3 | TN=7 | N=10 |
小计 | 鱼网里的:P’=12 | 鱼网外的N’ = 8 | 池塘大小=20 |
“鱼网”模型指标计算
正确率(Acc):(TP+TN )/(P+N) = (9+7) /(20) = 0.8
速记:分对的鱼和虾,占池塘总大小的比例
精确率(precision): TP/(TP+FP) = 9/12= 0.75
速记: 鱼网里鱼的比例
召回率(recall):TP/P = 9/10 = 0.9
速记: 捞到 (召回) 了全部鱼的多少比例
综合分类率:F1
F1 = 2 * (precision) * recall/(precision+recall)
= 2 * 0.75 * 0.9/(0.75+0.9)
= 0.8181
代码实现与验证
首先用一个列表来表示池塘,用1表示"鱼",用0表示"虾",
池塘里总共有10只鱼和10只虾,语句是这样子:
# 结果集 10个1表示10个鱼,10个0表示10个虾
y_test = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
再来看下鱼网的表示,“鱼网”抓住了12只动物,有9只是鱼,3只是虾,其它的没抓到。
这时需要与池塘的动物对应,可以认为前面9个鱼抓到了(是1),第10只鱼没抓到(是0),
接着有3只虾抓到了(是1),剩下的7只没有抓到(是0)。
表示的语句是这样的:
# 预测结果: 前面9个鱼正确,有1个鱼预测为虾,3个虾预测为鱼,7个虾预测为虾
y_pred = [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
接着使用代码来计算一下模型的各个指标,
# 模型评估报告
def model_score (y_test, y_pred):
# 开始计算指标
ACC = accuracy_score(y_test, y_pred)
PRECISION = precision_score (y_test, y_pred) #, average='macro' average='binary' 'weighted'
RECALL = recall_score (y_test, y_pred) #, average='macro'
F1 = f1_score (y_test, y_pred) #, average='macro'
ret = ""
ret += "准确度: %2.3f\n" % ( ACC )
ret += "精确度: %2.3f\n" % ( PRECISION )
ret += "召回率: %2.3f\n" % ( RECALL )
ret += "F1得分: %2.3f\n" % ( F1)
# 得到评价矩阵,注意这个结果与PPT中的表格不一样,是行列倒的,需要用.T转换一下
ret += str(confusion_matrix(y_test, y_pred).T) + '\n'
# 得到评价报告
ret += str(classification_report(y_test, y_pred))
return ret
report = model_score(y_test, y_pred)
print('模型评估报告'.center(40,'-')+'\n'+report)
运行结果如下图:
混淆矩阵热力图
最后使用代码来生成混淆矩阵的热力图:
def model_map (y_true, y_pred):
## 字体问题
sns.set(font='SimHei')
fig = plt.figure(figsize=(6,6))
##y轴显示真实值
y_true = ['鱼' if x else '虾' for x in y_true]
###显示预测值
y_pred = ['鱼' if x else '虾' for x in y_pred]
##分类标识
labels=['鱼','虾']
##构建混淆矩阵
C2= confusion_matrix(y_true, y_pred, labels=labels )
##print(C2)
##显示成热力图
ax=sns.heatmap(C2, annot=True, cmap='Greens', fmt='d', xticklabels=labels, yticklabels=labels)
ax.set_ylabel("真实")
ax.set_xlabel("预测")
ax.xaxis.set_label_position('top')
ax.xaxis.tick_top()
ax.set_title('混淆矩阵热力图', verticalalignment='bottom')
plt.savefig('map.png')
plt.show()
生成的热力图(如下图)与上面的分析表格一致,非常直观。
完整代码
最后附上完整的代码
#!/usr/bin/env python3
#coding:utf-8
__author__ = 'xmxoxo<xmxoxo@qq.com>'
# 模型评估指标 例子
import warnings
warnings.filterwarnings("ignore")
import numpy as np
import seaborn as sns;
from matplotlib import pyplot as plt
from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.metrics import f1_score, confusion_matrix, classification_report
# y_test = list('1'*10) + list('0'*10)
# 结果集 10个1表示10个鱼,10个0表示10个虾
y_test = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 预测结果: 前面9个鱼正确,有1个鱼预测为虾,3个虾预测为鱼,7个虾预测为虾
y_pred = [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
def model_map (y_true, y_pred):
## 字体问题
sns.set(font='SimHei')
fig = plt.figure(figsize=(6,6))
##y轴显示真实值
y_true = ['鱼' if x else '虾' for x in y_true]
###显示预测值
y_pred = ['鱼' if x else '虾' for x in y_pred]
##分类标识
labels=['鱼','虾']
##构建混淆矩阵
C2= confusion_matrix(y_true, y_pred, labels=labels )
##print(C2)
##显示成热力图
ax=sns.heatmap(C2, annot=True, cmap='Greens', fmt='d', xticklabels=labels, yticklabels=labels)
ax.set_ylabel("真实")
ax.set_xlabel("预测")
ax.xaxis.set_label_position('top')
ax.xaxis.tick_top()
ax.set_title('混淆矩阵热力图', verticalalignment='bottom')
plt.savefig('map.png')
plt.show()
# 模型评估报告
def model_score (y_test, y_pred):
# 开始计算指标
ACC = accuracy_score(y_test, y_pred)
PRECISION = precision_score (y_test, y_pred) #, average='macro' average='binary' 'weighted'
RECALL = recall_score (y_test, y_pred)
F1 = f1_score (y_test, y_pred)
ret = ""
ret += "准确度: %2.3f\n" % ( ACC )
ret += "精确度: %2.3f\n" % ( PRECISION )
ret += "召回率: %2.3f\n" % ( RECALL )
ret += "F1得分: %2.3f\n" % ( F1)
# 得到评价矩阵,注意这个结果与PPT中的表格不一样,是行列倒的,需要用.T转换一下
ret += str(confusion_matrix(y_test, y_pred).T) + '\n'
# 得到评价报告
ret += str(classification_report(y_test, y_pred))
return ret
report = model_score(y_test, y_pred)
print('模型评估报告'.center(40,'-')+'\n'+report)
model_map (y_test, y_pred)
if __name__ == '__main__':
pass
最后欢迎到 QQ群来沟通学习