为什么要用精确率和召回率
有这样一个训练集,1000个人参加了结直肠癌CRC的检测,实际有0.5%的人得了CRC(即5个人)。用神经网络算法得到检测这样一个训练集能达到99%的准确率。从数值上判断该算法是不错的,因为只有1%的误差。那么我们是否能应用该算法进行实际生产呢?这是不能的。因为如果误判一个人,对该人造成的影响是巨大的。如果不使用算法,直接预测这1000个人全没有得CRC,发现只有0.5的误差,比神经网络算法还好,这显然说明使用准确率在偏斜类样本集中判断算法好坏是不靠谱的。这时候,就需要使用精确率和召回率来判断了。
ps:偏斜类是指某类样品数量明显大于另一类样品
精确率和召回率
TP(True Positive): 实际为正类,预测为正类
TN(True Negative): 实际为正类,预测为负类
FP(False Positive): 实际为负类,预测为正类
FN(False Negative): 实际为正类,预测为负类
记忆 :T读成正确,F读成错误,P读成正类,F读成负类。例如,TP :正确的预测成正类,那么说明他实际也为正类
从混淆矩阵中得出对应的召回率和精确率在上例中代表的意思:
**召回率(recall)**为实际有CRC肿瘤的病人中,成功预测有CRC肿瘤的百分比,数值越大越好
**精确率(precision)**为预测的所有肿瘤病人中,实际上有肿瘤的病人,数值越大越好
这样,对于上面误差为1%的神经网络算法。TP
∈
\in
∈ [0,1,2,3,4,5] ,取最好的情况,假设5个病人全都预测出,即TP=5;因为1%的误差,则FP=10,FN=0,那么precision=5/(5+10)
≈
\approx
≈ 0.333…,说明该算法不好。
对于我们刚才那个总是预测病人没有CRC的方法,TP=0,召回率和精准率都是 0,直接排除。
F1值的由来
Algo | recall [R] | precision [P] |
---|---|---|
svm | 0.1 | 0.7 |
LR | 0.5 | 0.4 |
KNN | 0.02 | 1.0 |
以上3个算法得出的recall和precision,如何判断哪个算法更好。
如果用均值
P
+
R
2
\frac{P+R}{2}
2P+R 计算,svm=0.39,LR= 0.45,KNN=0.51,得出KNN算法最好,显然不对。
用
2
P
R
P
+
R
2\frac{PR}{P+R}
2P+RPR 计算,svm=0.175,LR= 0.44,KNN=0.03,得出LR算法最好,符合结果
sklearn中P/R/F1的micro,macro及weighted的算法
from sklearn.metrics import precision_score, recall_score, f1_score, confusion_matrix
y_pred = [ 0, 0, 0,1, 1, 1, 1, 1, 2, 2, 2 ]
y_true = [ 0, 1, 0, 1, 1, 2, 2, 2, 1, 0, 2 ]
confusion_matrix(y_true, y_pred )
array([[2, 0, 1],
[1, 2, 1],
[0, 3, 1]])
def precision(TP, FP):
return TP / (TP+FP)
def recall(TP, FN):
return TP/(TP+FN)
def F1(precision, recall):
return 2 * precision * recall / (precision + recall)
print(classification_report(y_true, y_pred))
p1 = precision(5, 6)
r1 = recall(5, 6)
f1 = F1(p1, r1)
p1, r1, f1
(0.45454545454545453, 0.45454545454545453, 0.45454545454545453)
p1 = precision(5, 6)
r1 = recall(5, 6)
f1 = F1(p1, r1)
p1, r1, f1
(0.45454545454545453, 0.45454545454545453, 0.45454545454545453)
precision_score(y_true, y_pred, average='micro')
recall_score(y_true, y_pred, average='micro')
f1_score(y_true, y_pred, average='micro')
0.45454545454545453
p0 = precision(2, 1) # 0 类精确率,TP表示实际为0类预测也为0类,从混淆矩阵中得值为2;
# FP表示实际为别类但是却错误的预测成了0类,从混淆矩阵中得值为1。
p1 = precision(2, 3)
p2 = precision(1, 2)
avg_p = (p0 + p1 + p2) / 3
r0 = recall(2, 1)
r1 = recall(2, 2)
r2 = recall(1, 3)
avg_r = (r0 + r1 + r2) / 3
f0 = F1(p0, r0)
f1 = F1(p1, r1)
f2 = F1(p2, r2)
avg_f = (f0 + f1 + f2) / 3
avg_p, avg_r, avg_f
(0.4666666666666666, 0.47222222222222215, 0.46560846560846564)
# y_true中 0类有3个,1类有4个,2类有4个
avg_p = 3/11 *p0 + 4/11*p1 + 4/11*p2
avg_r = 3/11*r0 + 4/11*r1 + 4/11* r2
avg_f = 3/11*f0 +4/11*f1 + 4/11*f2
avg_p, avg_r, avg_f
(0.4484848484848485, 0.4545454545454546, 0.44733044733044736)
-
precision_score,recall_score,f1_score中average='binary’的计算
- 只适用于二分类,用正类的y=1的TP,FP,FN来计算precision,recall,f1
y_pre = [ 0, 0, 0, 1, 1, 1, 1, 1 ]
y_tru = [ 0, 1, 0, 1, 1, 0, 0, 1 ]
precision_score(y_tru, y_pre, average='binary')
0.6
confusion_matrix(y_tru, y_pre)
array([[2, 2],
[1, 3]])
precision(3, 2)
0.6