scikit 学习的特殊性
Specificity in scikit learn
我的分类需要 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
变成了一系列的零
首先你需要知道:
DummyClassifier(strategy='most_frequent'...
将为您提供class识别器,其中return是您训练集中最常见的标签。它甚至不考虑 X 中的样本。您可以在此行中传递任何内容而不是 ground_truth:
clf_dummy = clf_dummy.fit(ground_truth, p)
训练和预测的结果将保持不变,因为 p 中的大多数标签是标签“0”。
第二个 你需要知道的事情:
make_scorer returns 函数与接口 scorer(estimator, X, y)
此函数将调用集合 X 上估计器的 predict 方法,并计算预测标签和 y 之间的特异性函数。
所以它在任何数据集上调用 clf_dummy(不管是哪个数据集,它总是 return 0)和 returns 向量 0,然后它计算特异性ground_truth 和预测之间的损失。您的预测为 0,因为 0 在训练集中占多数 class。您的分数等于 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)
您可以从 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)
据我了解,'specificity'只是'recall'的一个特例。召回是针对实际正数 class ( TP / [TP+FN] ) 计算的,而 'specificity' 是相同类型的计算,但针对实际负数 class ( TN / [TN+计划生育]).
对于二进制 class化问题,只有这样的特定术语才有意义。对于 multi-class class 化问题,讨论每个 class 的召回会更方便。即使在处理二进制 class 化问题时,也没有理由不能以这种方式谈论召回(例如召回 class 0,召回 class 1)。
例如,召回率告诉我们实际患有癌症并被成功诊断为患有癌症的患者比例。但是,概括地说,您可以说 Class X 召回率告诉我们实际上属于 Class X 的样本比例,被成功预测为属于 Class X。
鉴于此,您可以使用 from sklearn.metrics import classification_report
生成 dictionary of the precision, recall, f1-score and support for each label/class. You can also rely on from sklearn.metrics import precision_recall_fscore_support
as well, depending on your preference. Documentation here。
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
记住在二进制class化中,正class的召回也被称为“敏感性”;回忆负数 class 是“特异性”,我用这个:
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))
正如其他答案中提到的,特异性是对负面因素的回忆class。您只需设置 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)
其中 returns .25
.
我个人非常依赖 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)
我的分类需要 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
变成了一系列的零
首先你需要知道:
DummyClassifier(strategy='most_frequent'...
将为您提供class识别器,其中return是您训练集中最常见的标签。它甚至不考虑 X 中的样本。您可以在此行中传递任何内容而不是 ground_truth:
clf_dummy = clf_dummy.fit(ground_truth, p)
训练和预测的结果将保持不变,因为 p 中的大多数标签是标签“0”。
第二个 你需要知道的事情:
make_scorer returns 函数与接口 scorer(estimator, X, y)
此函数将调用集合 X 上估计器的 predict 方法,并计算预测标签和 y 之间的特异性函数。
所以它在任何数据集上调用 clf_dummy(不管是哪个数据集,它总是 return 0)和 returns 向量 0,然后它计算特异性ground_truth 和预测之间的损失。您的预测为 0,因为 0 在训练集中占多数 class。您的分数等于 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)
您可以从 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)
据我了解,'specificity'只是'recall'的一个特例。召回是针对实际正数 class ( TP / [TP+FN] ) 计算的,而 'specificity' 是相同类型的计算,但针对实际负数 class ( TN / [TN+计划生育]).
对于二进制 class化问题,只有这样的特定术语才有意义。对于 multi-class class 化问题,讨论每个 class 的召回会更方便。即使在处理二进制 class 化问题时,也没有理由不能以这种方式谈论召回(例如召回 class 0,召回 class 1)。
例如,召回率告诉我们实际患有癌症并被成功诊断为患有癌症的患者比例。但是,概括地说,您可以说 Class X 召回率告诉我们实际上属于 Class X 的样本比例,被成功预测为属于 Class X。
鉴于此,您可以使用 from sklearn.metrics import classification_report
生成 dictionary of the precision, recall, f1-score and support for each label/class. You can also rely on from sklearn.metrics import precision_recall_fscore_support
as well, depending on your preference. Documentation here。
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
记住在二进制class化中,正class的召回也被称为“敏感性”;回忆负数 class 是“特异性”,我用这个:
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))
正如其他答案中提到的,特异性是对负面因素的回忆class。您只需设置 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)
其中 returns .25
.
我个人非常依赖 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)