我使用了 sklearn.metrics.jaccard_score
来获取我的 Python 模型二分类测试的相关得分。它输出的结果如下所示,但是当我手动计算这个指标时,得出的值却不同。我是否误解了这个函数中“jaccard”的含义?还是我使用的方式不对?sklearn 函数收集的所有其他指标都返回了正确的值。以下是我的代码,包括手动测试 jaccard 的部分(通过在计算器上将向量作为集合进行比较,得出的结果相同,这让我稍微松了一口气)。
def test(X, y, model): predictions = model.predict(X, verbose=1).ravel() report = classification_report(y, predictions, target_names=['nao_doentes', 'doentes']) confMatrix = confusion_matrix(y, predictions) tn, fp, fn, tp = confMatrix.ravel() jaccard = jaccard_score(y, predictions) # 表现得有些奇怪 print(tn, fp, fn, tp) print(predictions) print(y) print(report) print(confMatrix) print("Jaccard by function: {}".format(jaccard)) # 注意,在二分类中,正类的召回率也被称为“灵敏度”;负类的召回率被称为“特异度”。 dice = ((2*tp) / ((2*tp) + fp + fn)) jaccard = ((tp + tn) / ((2*(tp + tn + fn + fp)) - (tp + tn))) print(dice) print("Jaccard by hand: {}".format(jaccard))
接下来是输出结果:
2 0 1 1[1. 0. 0. 0.][1 0 1 0] precision recall f1-score support nao_doentes 0.67 1.00 0.80 2 doentes 1.00 0.50 0.67 2 accuracy 0.75 4 macro avg 0.83 0.75 0.73 4weighted avg 0.83 0.75 0.73 4[[2 0] [1 1]]Jaccard by function: 0.50.6666666666666666Jaccard by hand: 0.6
第二个问题是,为什么 classification_report
似乎将 nao_doentes
(葡萄牙语中的非病人)标记为 1,而将 doentes
(病人)标记为 0?不应该是相反的吗?在我的集合中(也就是在 y 中),nao_doentes
被设为 0,doentes
被设为 1。
回答:
查看帮助页面,jaccard 得分定义为:
两个标签集合的交集的大小除以它们的并集的大小,
他们只关注正类:
如果某些样本或类别没有正例,jaccard_score 可能是一个不好的指标。如果没有真实的或预测的标签,jaccard 是未定义的,我们的实现将返回一个带有警告的 0 分数。
在你给出的混淆矩阵中,你有:
intersection = tp # 你有 1union = tp+fp # 你有 2 jaccard = intersection / union
这应该给你 1 / (1+1) = 0.5 。
你的标签是正确的。你可以转换标签,你会发现你得到相同的混淆矩阵:
import pandas as pdlabels = pd.Categorical(['nao_doentes','doentes'],categories=['nao_doentes','doentes'])prediction = [1 ,0 ,0, 0]y = [1 ,0, 1, 0]pd.crosstab(labels[y],labels[prediction])col_0 nao_doentes doentesrow_0 nao_doentes 2 0doentes 1 1