在机器学习领域,分类问题的性能评估常通过混淆矩阵来实现。混淆矩阵中的元素帮助计算出三个重要的参数:准确率、敏感性和特异性。这些参数基于数据中类别之间的最优边界预测。本文将解释敏感性、特异性与准确率之间的关系,以及它们如何共同帮助确定最优边界。
在任何机器学习模型中,通常关注准确率。但如果处理的是分类问题,还需要担心正确分类和错误分类的百分比。因此,需要一种机制,它不仅提供准确率,还有助于估计正确分类和错误分类。混淆矩阵就是这样一种工具。它是一个NxN的矩阵,用于评估机器学习模型在分类问题上的性能。图1展示了二分类问题的混淆矩阵。
混淆矩阵中的元素如下:
TP = True Positive(真正例)
TN = True Negative(真负例)
FP = False Positive(假正例)
FN = False Negative(假负例)
准确率、敏感性和特异性的计算公式如下:
准确率公式
敏感性公式
特异性公式
将通过一个简单的二分类问题来计算混淆矩阵,并评估准确率、敏感性和特异性。基于血糖水平数据预测患者是否患有糖尿病。
数据集 - 下载 diabetes_data.csv
。这个数据集是Kaggle上可用的糖尿病数据的简化版本。将逐步构建模型并计算混淆矩阵。
import pandas as pdimport numpy as npdib = pd.read_csv('diabetes_data.csv') # 导入数据到名为dib的数据框dib.shape # 了解数据框的形状(768, 2) # 数据集有768行和2列dib.head() # 查看几行
数据集包含两列。糖尿病是因变量或响应变量。血糖水平是自变量或特征变量,用于预测糖尿病。
对数据集进行一些修改,使其适合建模
dib['Diabetes'] = dib['Diabetes'].map({'Yes': 1, 'No': 0}) # 将Yes转换为1,No转换为0X = dib['Blood Sugar Level'] # 将特征变量放入Xy = dib['Diabetes'] # 将响应变量放入y
数据框dib将被分为训练集和测试集。训练集将用于构建模型
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, test_size=0.3, random_state=100)
import statsmodels.api as smX_train_sm = sm.add_constant(X_train)logm2 = sm.GLM(y_train,X_train_sm, family = sm.families.Binomial())res = logm2.fit()res.summary()y_train_pred = res.predict(X_train_sm) # 预测血糖水平
基于训练数据,将创建一个新的数据框dib_train,其中包含原始和预测的糖尿病数据
data = {'Blood Sugar Level':X_train, 'Diabetes':y_train, 'y_train_pred':y_train_pred}dib_train = pd.DataFrame(data)
基于0.5的截止概率创建预测糖尿病
dib_train['Diabetes_predicted'] = dib_train.y_train_pred.map(lambda x: 1 if x > 0.5 else 0)dib_train.head()
从表中可以看出,存在一定的错误预测或误分类。正确分类和误分类由混淆矩阵确定。误分类的百分比取决于截止选择。将在接下来的步骤中评估最优截止。
现在让评估混淆矩阵
from sklearn import metricsconfusion = metrics.confusion_matrix(dib_train.Diabetes, dib_train.Diabetes_predicted)print(confusion)[[309 41][ 96 91]]
让检查整体准确率。
print(metrics.accuracy_score(dib_train.Diabetes, dib_train.Diabetes_predicted))0.74487895716946
到目前为止,已经用截止=0.5计算了混淆矩阵和准确率。这假设数据正好在0.5概率处被分割。现在让将概率从0.1变化到0.9。
numbers = [float(x)/10 for x in range(10)]for i in numbers: dib_train[i]= dib_train.y_train_pred.map(lambda x: 1 if x > i else 0)dib_train.head()
从混淆矩阵中,可以计算出不同截止概率下的敏感性、特异性和准确率。
from sklearn.metrics import confusion_matrixnum = [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]for i in num: cm1 = metrics.confusion_matrix(dib_train.Diabetes, dib_train[i]) total1=sum(sum(cm1)) Accuracy = (cm1[0,0]+cm1[1,1])/total1 Specificity = cm1[0,0]/(cm1[0,0]+cm1[0,1]) Sensitivity = cm1[1,1]/(cm1[1,0]+cm1[1,1]) cutoff_df.loc[i] =[ i ,Accuracy,Sensitivity,Specificity]
通过绘制敏感性、特异性和准确率与各种截止值的关系图,可以看到它们的变化。从图中还可以看出敏感性和特异性是成反比的。敏感性和特异性曲线相交的点给出了最优截止值。对于上述图表,这个值是0.32。让计算在最优点的敏感性、特异性和准确率的值。
dib_train['Diabetes_predicted'] = dib_train.y_train_pred.map(lambda x: 1 if x > 0.32 else 0)print(metrics.accuracy_score(dib_train.Diabetes, dib_train.Diabetes_predicted))0.7281191806331471confusion = metrics.confusion_matrix(dib_train.Diabetes, dib_train.Diabetes_predicted)print(confusion)[[253 97][ 49 138]]
TP = confusion[1,1] # 真正例TN = confusion[0,0] # 真负例FP = confusion[0,1] # 假正例FN = confusion[1,0] # 假负例
让看看逻辑回归模型的敏感性
TP / float(TP+FN)0.7379679144385026
让计算特异性
TN / float(TN+FP)0.7228571428571429
可以看到,在最优截止点,敏感性和特异性的值彼此接近。
本文介绍了分类问题中敏感性、特异性与准确率之间的关系。敏感性和特异性成反比,它们的图表与截止点相交。交点提供了创建类别边界的最优截止。在最优截止或交点处,敏感性和特异性相等。通过数学推导,还看到在最优截止点,准确率也等于敏感性和特异性。
Q1. 特异性的公式是什么?
A. 特异性的公式如下:
特异性= 真负例 / (真负例 + 假正例)
敏感性 = 真正例 / (真正例 + 假负例)