计算accuracy_top-1、accuracy_top-5、precision、recall和f1_score:
(1)accuracy_top-1
np.sum(np.argmax(preds, axis=1) == np.argmax(actual, axis=1)) / actual.shape[0]
accuracy_top-1指标是假设预测数据中,最大值的index就是预测出来的样本类别,从而看一下总共预测正确了多少个样本,再除以总数量即是accuracy_top-1指标。
(2)accuracy_top-5
np.sum(np.argsort(preds, axis=1)[:, -1:-5:-1] == np.argmax(actual, axis=1).reshape(-1, 1)) / actual.shape[0]
和accuracy_top-1类似,也是先将预测出的多个概率值排序,但取最大的五个的index,只要有一个index能对上真实的label,那就是预测准确。预测正确的样本数再除以总数量即是accuracy_top-1指标。
有个风险是,有时候类别数量小于5,这样怎么算accuracy_top-5的数值都会是100%。
(3)precision、recall、f1_score
这都是在引入threshold 数值之后才能计算的。
precision = tp / (tp + fp) # 预测正确数量/所有的预测数量
recall = tp / (tp + fn) # 预测正确数量/所有的实际数量
f1_score = 2 * precision * recall / (precision + recall)
“所有的预测数量” 和 “所有的实际数量” 都不是我们的总样本数量,当一个样本输入模型,模型的结果中,如果几个类别的预测值都小于预测值,那么这个样本就不会纳入到这里“precision、recall或f1_score”的计算。
那么Why? 因为我们是在评估模型的方面的指标,评估模型的指标就是这样计算。而总样本数量不会影响模型的指标,但是会影响模型的泛化性能。
下面的程序中,构建好实际labels和预测preds,即可计算出所有指标:
import numpy as np
n_samples = 10000 # 假设总样本个数
cls_n = 6 # 假设模型类别个数
threshold = 0.5 # 阈值
# n_samples行,6列,每一行只有一个数字是1
actual = np.zeros((n_samples, cls_n))
actual[np.arange(n_samples), np.random.randint(0, cls_n, n_samples)] = 1
# 7个样本是7行, 6个类别是6列
# 高斯分布
preds = np.random.randn(n_samples, cls_n)
sums = preds.sum(axis=1) # 求每行的和
preds /= sums[:, None] # 每行除以自己的和
# 计算accuracy_top-1
top1_acc = np.sum(np.argmax(preds, axis=1) == np.argmax(actual, axis=1)) / actual.shape[0]
print("accuracy_top-1", top1_acc)
# 计算accuracy_top-5
top5_acc = np.sum(np.argsort(preds, axis=1)[:, -1:-5:-1] == np.argmax(actual, axis=1).reshape(-1, 1)) / actual.shape[0]
print("accuracy_top-5", top5_acc)
# 计算各个类别precision, recall和f1 score
for i in range(actual.shape[1]):
tp = np.sum(np.logical_and(preds[:, i] >= threshold, actual[:, i] == 1))
fp = np.sum(np.logical_and(preds[:, i] >= threshold, actual[:, i] == 0))
fn = np.sum(np.logical_and(preds[:, i] < threshold, actual[:, i] == 1))
if tp == 0 or tp + fp == 0:
precision = 0
else:
precision = tp / (tp + fp) # 预测正确数量/所有的预测数量
if tp == 0 or tp + fn == 0:
recall = 0
else:
recall = tp / (tp + fn) # 预测正确数量/所有的实际数量
if precision + recall == 0:
f1_score = 0
else:
f1_score = 2 * precision * recall / (precision + recall)
print("class", i, "precision", round(precision, 4), "recall", round(recall, 4), "f1_score", round(f1_score, 4))