灵敏度(sensitivity)和特异性(specificity)的计算

本文深入探讨了医学统计学中的灵敏度与特异性概念,详细解释了它们的计算方式及意义,旨在帮助读者理解这两种指标如何评估诊断测试的准确性。

最近查看文献,发现了文献中灵敏度与特异性的计算有点问题,特意查了一下,结论如下:

 

灵敏度=真阳性人数/(真阳性人数+假阴性人数)*100%。正确判断病人的率;
特异度=真阴性人数/(真阴性人数+假阳性人数))*100%。正确判断非病人的率;其中真阳性、假阴性、真阴性和假阳性均为检测值,具体参考《全国医学成人高等教育专科教材 医学统计学 (第二版)》下图:

 

灵敏度sensitivity和特异性specificity的计算


http://en.wikipedia.org/wiki/Sensitivity_and_specificity维基百科里的解释也很让人费解。

<think> 我们正在处理一个多分类问题。在二分类中,灵敏度特异度定义明确,但在多分类中,我们通常有两种方式: 1. 对每个类别单独计算(一对多策略):将当前类视为正类,其余所有类视为负类,然后计算该类的灵敏度特异度。 2. 整体计算:但通常多分类的灵敏度特异度是按类别分别计算的。 根据引用[2],它提到了计算三分类模型每一类对应的特异度、灵敏度。因此,我们将采用第一种方法:对于每个类别,将其视为正类,其他类别视为负类,然后计算该类的灵敏度(召回率)特异度。 定义: 对于第i类: - TP_i: 将第i类正确预测为第i类的样本数。 - TN_i: 将非第i类正确预测为非第i类的样本数(即其他类别的样本被预测为其他类别)。 - FP_i: 将非第i类错误预测为第i类的样本数。 - FN_i: 将第i类错误预测为非第i类的样本数。 灵敏度Sensitivity)即召回率(Recall): Sensitivity_i = TP_i / (TP_i + FN_i) 特异度(Specificity): Specificity_i = TN_i / (TN_i + FP_i) 另外,引用[2]还提到了PPV(阳性预测值,即精确率Precision)NPV(阴性预测值): PPV_i = TP_i / (TP_i + FP_i) NPV_i = TN_i / (TN_i + FN_i) 在多分类问题中,我们通常使用混淆矩阵来获取TP, TN, FP, FN的值。 步骤: 1. 计算整个混淆矩阵(C),其中行表示真实类别,列表示预测类别。 2. 对于每个类别i: TP_i = C[i, i] FP_i = 第i列的总(所有预测为i的样本)减去 TP_i FN_i = 第i行的总(所有真实为i的样本)减去 TP_i TN_i = 总样本数减去(TP_i+FP_i+FN_i) 或者,直接计算:所有非i类别的样本中,预测为非i类的数量(即混淆矩阵中去除第i行第i列的所有元素之) 但是,更直接的计算TN_i的方法是: TN_i = 总样本数 - TP_i - FP_i - FN_i ??? 不对,因为TN_i是负类正确预测的数量,它等于所有非i类样本中预测为非i类的样本数。 另一种计算TN_i的方法:将所有真实标签为非i的样本中,预测标签为非i的样本数加起来。这等于: TN_i = 所有真实类别为j(j≠i)的样本中,预测类别为k(k≠i)的样本数之。 实际上,我们可以通过整个混淆矩阵的减去第i行(真实为i的样本)第i列(预测为i的样本),再加上TP_i(因为减了两次)?不对,更简单的是:整个混淆矩阵的总(总样本数)减去第i行的(真实为i的样本数)再减去第i列的(预测为i的样本数)再加上TP_i(因为减了两次TP_i)。所以: TN_i = 总样本数 - (真实为i的样本数) - (预测为i的样本数) + TP_i 但注意:真实为i的样本数 = TP_i + FN_i 预测为i的样本数 = TP_i + FP_i TN_i = 总样本数 - (TP_i+FN_i) - (TP_i+FP_i) + TP_i = 总样本数 - TP_i - FN_i - FP_i 所以,这个公式是成立的。但是,我们通常直接使用混淆矩阵来计算。 在代码中,如果我们有一个混淆矩阵`cm`(numpy数组),其中行是真实标签,列是预测标签,类别数为n。 那么对于类别i(索引从0到n-1): TP_i = cm[i, i] FP_i = cm[:, i].sum() - TP_i # 所有预测为i的样本中,真实不是i的(即FP_i) FN_i = cm[i, :].sum() - TP_i # 所有真实为i的样本中,预测不是i的(即FN_i) TN_i = cm.sum() - (TP_i + FP_i + FN_i) # 因为总样本数减去正类样本(真实为i)预测为正类的样本(预测为i)会多减了TP_i,但这里我们直接使用上面的推导:总样本数减去TP,FP,FN 注意:总样本数 = cm.sum() 因此,我们可以这样计算每个类别的指标。 另外,引用[2]提到使用Bootstrap抽样来计算置信区间。这里我们也可以介绍,但用户主要问的是计算方法实现代码,我们先给出基本计算,然后如果需要置信区间再介绍Bootstrap方法。 实现步骤: 1. 获取真实标签预测标签。 2. 计算混淆矩阵(可以使用sklearn的confusion_matrix)。 3. 对每个类别,计算TP, FP, TN, FN。 4. 计算灵敏度、特异度、PPV、NPV。 下面我们用代码实现(多分类,假设类别标签从0开始连续整数): 注意:如果类别不是连续整数,我们需要先将其映射为连续整数(0到n-1),或者确保混淆矩阵的行列顺序与类别标签顺序一致。 另外,我们也可以使用sklearn的precision_recall_fscore_support等函数,但这里我们需要特异度NPV,所以需要自己计算。 我们写一个函数,输入:真实标签y_true,预测标签y_pred,类别列表(可选,如果不提供则从y_true中获取唯一值并排序) 输出:一个字典,键为类别,值为一个包含该类别灵敏度、特异度、PPV、NPV的字典。 另外,我们可以提供计算置信区间的选项(使用bootstrap抽样),但根据引用[2],我们可以用bootstrap抽样来估计置信区间。这里我们先实现基本计算,然后如果需要置信区间再扩展。 由于问题要求多分类,我们按照上述方法实现。 代码示例: </think> ### Python中多分类灵敏度特异度的计算与实现 在Python中计算多分类问题的灵敏度特异度,核心是**按类别进行"一对多"(OvR)分解**。以下是完整的计算方法与实现示例: #### 1. **核心概念定义** - **灵敏度(召回率)**:$Sensitivity_i = \frac{TP_i}{TP_i + FN_i}$ (第$i$类正确识别数 / 所有真实$i$类样本数) - **特异度**:$Specificity_i = \frac{TN_i}{TN_i + FP_i}$ (非$i$类正确识别数 / 所有非$i$类样本数) 其中: - $TP_i$:真实为$i$类且预测为$i$类的样本数 - $TN_i$:真实非$i$类且预测非$i$类的样本数 - $FP_i$:真实非$i$类但预测为$i$类的样本数 - $FN_i$:真实为$i$类但预测非$i$类的样本数 #### 2. **计算方法(基于混淆矩阵)** 假设有$n$个类别,混淆矩阵$C$为$n \times n$矩阵: ```python 示例混淆矩阵(3分类): 预测0 预测1 预测2 真实0 [ 10 1 2 ] 真实1 [ 0 8 1 ] 真实2 [ 1 2 9 ] ``` 计算**类别0**的指标: - $TP_0 = 10$ - $FN_0 = 1 + 2 = 3$ - $FP_0 = 0 + 1 = 1$ - $TN_0 = (8+1) + (2+9) = 20$ - $Sensitivity_0 = 10/(10+3) ≈ 0.769$ - $Specificity_0 = 20/(20+1) ≈ 0.952$ #### 3. **Python实现代码** ```python import numpy as np from sklearn.metrics import confusion_matrix def multiclass_sensitivity_specificity(y_true, y_pred): """ 计算多分类中每个类别的灵敏度特异度 参数: y_true: 真实标签数组, shape=(n_samples,) y_pred: 预测标签数组, shape=(n_samples,) 返回: dict: {类别: {"Sensitivity": val, "Specificity": val}} """ cm = confusion_matrix(y_true, y_pred) n_classes = cm.shape[0] results = {} for i in range(n_classes): TP = cm[i, i] FN = np.sum(cm[i, :]) - TP # 第i行非对角线之 FP = np.sum(cm[:, i]) - TP # 第i列非对角线之 TN = np.sum(cm) - (TP + FP + FN) # 总数减去其他项 sensitivity = TP / (TP + FN) if (TP + FN) > 0 else 0 specificity = TN / (TN + FP) if (TN + FP) > 0 else 0 results[f"Class_{i}"] = { "Sensitivity": round(sensitivity, 4), "Specificity": round(specificity, 4) } return results # 示例使用 y_true = [0, 0, 0, 1, 1, 2, 2, 2] y_pred = [0, 0, 1, 1, 2, 0, 2, 2] print(multiclass_sensitivity_specificity(y_true, y_pred)) ``` **输出示例**: ``` { 'Class_0': {'Sensitivity': 0.6667, 'Specificity': 0.8}, 'Class_1': {'Sensitivity': 0.5, 'Specificity': 0.8333}, 'Class_2': {'Sensitivity': 0.6667, 'Specificity': 0.8} } ``` #### 4. **扩展指标计算(PPV/NPV)** 在返回字典中可添加阳性预测值(PPV)阴性预测值(NPV): ```python PPV = TP / (TP + FP) # 精确率(Precision) NPV = TN / (TN + FN) ``` #### 5. **置信区间计算(Bootstrap法)** 引用[2]提到的Bootstrap抽样法可实现置信区间估计: ```python from sklearn.utils import resample def bootstrap_metrics(y_true, y_pred, n_bootstraps=1000, alpha=0.95): metrics = [] for _ in range(n_bootstraps): # 重抽样 idx = resample(np.arange(len(y_true))) res = multiclass_sensitivity_specificity(y_true[idx], y_pred[idx]) metrics.append(res) # 计算每个类别的置信区间 ci_results = {} for class_name in metrics[0].keys(): sens_vals = [m[class_name]["Sensitivity"] for m in metrics] spec_vals = [m[class_name]["Specificity"] for m in metrics] # 取α/21-α/2分位数 ci_low = (1 - alpha) / 2 ci_high = 1 - ci_low ci_results[class_name] = { "Sensitivity_CI": (np.quantile(sens_vals, ci_low), np.quantile(sens_vals, ci_high)), "Specificity_CI": (np.quantile(spec_vals, ci_low), np.quantile(spec_vals, ci_high)) } return ci_results ``` #### 6. **注意事项** - 类别平衡:数据不均衡时建议同时报告加权平均结果 - 多分类指标:完整评估应包含宏平均/微平均(`sklearn.metrics.classification_report`) - 实践建议:优先使用`sklearn.metrics.recall_score`计算灵敏度(召回率)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值