scikit学习的特异性



我需要specificity为我的分类,定义为:TN/(TN+FP)

我正在写一个自定义分数函数:

from sklearn.metrics import make_scorer
def specificity_loss_func(ground_truth, predictions):
    print predictions
    tp, tn, fn, fp = 0.0,0.0,0.0,0.0
    for l,m in enumerate(ground_truth):        
        if m==predictions[l] and m==1:
            tp+=1
        if m==predictions[l] and m==0:
            tn+=1
        if m!=predictions[l] and m==1:
            fn+=1
        if m!=predictions[l] and m==0:
            fp+=1
    `return tn/(tn+fp)
score = make_scorer(specificity_loss_func, greater_is_better=True)

,

from sklearn.dummy import DummyClassifier
clf_dummy = DummyClassifier(strategy='most_frequent', random_state=0)
ground_truth = [0,0,1,0,1,1,1,0,0,1,0,0,1]
p  = [0,0,0,1,0,1,1,1,1,0,0,1,0]
clf_dummy = clf_dummy.fit(ground_truth, p)
score(clf_dummy, ground_truth, p)

当我运行这些命令时,我得到p打印为:

[0 0 0 0 0 0 0 0 0 0 0 0 0]
1.0

当我输入p = [0,0,0,1,0,1,1,1,1,0,0,1,0]

时,为什么我的p变为一系列零

您可以从confusion matrix中获得specificity。对于二元分类问题,它类似于:

from sklearn.metrics import confusion_matrix
y_true = [0, 0, 0, 1, 1, 1, 1, 1]
y_pred = [0, 1, 0, 1, 0, 1, 0, 1]
tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
specificity = tn / (tn+fp)

正如在其他回答中提到的,特异性是对否定类的回忆。您可以通过设置pos_label参数来实现:

from sklearn.metrics import recall_score
y_true = [0, 1, 0, 0, 1, 0]
y_pred = [0, 0, 1, 1, 1, 1]
recall_score(y_true, y_pred, pos_label=0)

返回.25

首先你需要知道:

DummyClassifier(strategy='most_frequent'...

将给你从你的训练集中返回最频繁标签的分类器。它甚至不考虑x中的样本。您可以在这一行传递任何东西而不是ground_truth:

clf_dummy = clf_dummy.fit(ground_truth, p)

训练结果,和预测结果将保持不变,因为p内的大多数标签都是标签"0"。

第二个你需要知道的事情:make_scorer返回接口为scorer(estimator, X, y)的函数,该函数将调用集合X上estimator的predict方法,并计算预测标签与y之间的特异性函数。

所以它在任何数据集上调用clf_dummy(不管哪个数据集,它总是返回0),并返回0的向量,然后它计算ground_truth和预测之间的特异性损失。你的预测是0因为0是训练集中的多数类。你的分数等于1,因为没有假阳性预测。

我修改了你的代码,以增加更多的方便。

from sklearn.dummy import DummyClassifier
clf_dummy = DummyClassifier(strategy='most_frequent', random_state=0)
X = [[0],[0],[1],[0],[1],[1],[1],[0],[0],[1],[0],[0],[1]]
p  = [0,0,0,1,0,1,1,1,1,0,0,1,0]
clf_dummy = clf_dummy.fit(X, p)
score(clf_dummy, X, p)

在我的理解中,"专一性"只是"回忆"的一个特例。召回率是针对实际阳性类别(TP/[TP+FN])计算的,而"特异性"是相同类型的计算,但针对实际阴性类别(TN/[TN+FP])。

只有在二元分类问题中使用这种特定的术语才有意义。对于一个多类分类问题,讨论每个类的召回率会更方便。即使在处理二元分类问题(例如,类0的召回,类1的召回)时,也没有理由不能以这种方式谈论召回。

例如,回忆告诉我们实际患有癌症的患者被成功诊断为患有癌症的比例。然而,概括地说,你可以说X类召回率告诉我们实际属于X类的样本的比例,被成功地预测为属于X类。

考虑到这一点,您可以使用from sklearn.metrics import classification_report生成每个标签/类的精度、召回率、f1-score和支持度的字典。您也可以依赖from sklearn.metrics import precision_recall_fscore_support,这取决于您的偏好。文档在这里。

from sklearn.metrics import precision_recall_fscore_support
labels = ['dog', 'cat', 'pig']
y_true = np.array(['cat', 'dog', 'pig', 'cat', 'dog', 'pig'])
y_pred = np.array(['cat', 'pig', 'dog', 'cat', 'cat', 'dog'])
prfs = precision_recall_fscore_support(y_true, y_pred, average=None, labels=labels)
precisions = prfs[0]
recalls = prfs[1] #Specificity in Binary Classification
fbeta_scores = prfs[2]
supports = prfs[3]
print(recalls) # Note the order of this array is dependent on the order of your labels array

记住,在二元分类中,正类的召回也被称为"灵敏度";回忆的否定类是"专一性",我用这个:

unique, counts = np.unique(y_test, return_counts=True)
for i in unique:
    score = precision_score(y_true, y_pred, labels=unique, pos_label=i)
    print('score ' + str(i) + '  ' + str(score))

我个人非常依赖使用sklearn的classification_report,所以想用特定的值来扩展它,所以想出了下面的代码。

请注意,我只将其添加到macro avg中,尽管将其扩展到加权平均输出也应该很容易

import random
import numpy as np
from sklearn.metrics import classification_report
def extended_classification_report(y_true: np.array, y_pred: np.array, classes: set = None):
    report = classification_report(y_true, y_pred, output_dict=True, zero_division=0)
    report['macro avg']['specificity'] = specificity(y_true, y_pred, classes=classes)
    return report

def specificity(y_true: np.array, y_pred: np.array, classes: set = None):
    if classes is None: # Determine classes from the values
        classes = set(np.concatenate((np.unique(y_true), np.unique(y_pred))))
    specs = []
    for cls in classes:
        y_true_cls = (y_true == cls).astype(int)
        y_pred_cls = (y_pred == cls).astype(int)
        fp = sum(y_pred_cls[y_true_cls != 1])
        tn = sum(y_pred_cls[y_true_cls == 0] == False)
        specificity_val = tn / (tn + fp)
        specs.append(specificity_val)
    return np.mean(specs)

相关内容

  • 没有找到相关文章

最新更新