P-R曲线绘制原理及代码实现

简介

P-R曲线,是指以查准率(亦称准确率)为纵轴、查全率(亦称召回率)为横轴画出的曲线,反映了查准率随查全率的变化趋势,在机器学习中常用于二分类模型的评价及选择。

相关概念

混淆矩阵

实际为负实际为正
预测为负TNFP
预测为正FNTP

查准率(亦称准确率)

p r e c i s i o n = T P T P + F P precision = \frac{TP}{TP+FP} precision=TP+FPTP

查全率(亦称召回率)

r e c a l l = T P T P + F N recall = \frac{TP}{TP+FN} recall=TP+FNTP

绘制原理

在训练集上训练出二分类模型后我们将测试集中的数据输入模型,这时我们可以计算得到这些数据属于某个类别的概率,将这些预测概率从小到大排列,然后将分类阈值依次设为[0,1]区间中不同的概率值并计算这时的准确率和召回率,最后将这些准确率和召回率在二维坐标系中连起来就得到了ROC曲线

示例

为了说明计算细节,这里使用一个虚构的例子:假设数据集有两个特征,分别是length和width,取值都是整数,标签有两类,分别是0和1,并且类别1是正类(positive);假设我们在这个数据集上训练得到的树模型如下:
在这里插入图片描述

并且我们假设训练数据在叶节点的分布如下:

叶节点编号类别为0的样本个数类别为1的样本点个数该叶节点属于类别0的概率该叶节点属于类别1的概率该叶节点预测类别
19001000.90.10
26002000.750.250
3509500.050.951

其中

某 叶 节 点 属 于 类 别 1 的 概 率 = 落 在 该 节 点 的 真 实 类 别 为 1 的 样 本 数 落 在 该 节 点 的 总 样 本 数 某叶节点属于类别1的概率=\frac{落在该节点的真实类别为1的样本数}{落在该节点的总样本数} 1=1

并且叶节点的预测类别为它的所属概率更大的那个类别

假设测试集为:

特征测试数据1测试数据2测试数据3测试数据4测试数据5测试数据6测试数据7测试数据8测试数据9测试数据10
length21561711591012
width4861913218329
实际所属类别0111101000

按照我们决策树的划分,可以得到测试集属于正类(类别1)的概率分别为(例如测试数据1最终被分到了叶节点2,那么它属于类别1的概率就是叶节点2属于类别1的概率):

测试数据1测试数据2测试数据3测试数据4测试数据5测试数据6测试数据7测试数据8测试数据9测试数据10
0.250.10.250.950.950.250.950.10.10.1

将他们按概率大小排列得到:

测试数据 10测试数据9测试数据8测试数据2测试数据1测试数据3测试数据6测试数据4测试数据5测试数据7
属于正类的概率0.10.10.10.10.250.250.250.950.950.95
实际所属类别0001010111

现在我们将分类阈值分别设为0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,并将概率大于阈值的测试样本预测为类别1,可以得到不同分类阈值下的准确率和召回率:

分类阈值TPFNFP准确率召回率
05050.51
0.14120.670.8
0.24120.670.8
0.332010.6
0.432010.6
0.532010.6
0.632010.6
0.732010.6
0.832010.6
0.932010.6

将(召回率,准确率)在坐标中画出来就得到了P-R曲线:
在这里插入图片描述
可见我们虚构的模型表现不太理想

代码实现

自己写代码

我们以sklearn.datasets中的乳腺癌数据集为例,这是一个二分类数据集,我们将在这个数据集上学习一个分类树模型并绘制该模型的P-R曲线:

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
import matplotlib.pyplot as plt
import numpy as np

data = load_breast_cancer()
X = data.data
y = data.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=66)

dtc = DecisionTreeClassifier(min_samples_leaf=10)
dtc.fit(X_train, y_train)

# predict_proba返回的是每个样本分别属于两个类别的概率,而我们只关心它属于正类的概率
probs = dtc.predict_proba(X_test)[:, 1]

# 就像在上面那个虚构的例子中展示的那样,
# 决策树在做预测时对每个样本会算出它属于两个类别的概率,
# 最终预测结果就是预测概率大于0.5的那个类
y_predict = dtc.predict(X_test)

# 人为地生成一系列不同的阈值
thresholds = np.arange(np.min(probs), np.max(probs), 0.1)

precisions = []
recalls = []
for threshold in thresholds:
    y_predict = np.array(probs >= threshold, dtype='int')
    pre = precision_score(y_test, y_predict)
    recall = recall_score(y_test, y_predict)
    precisions.append(pre)
    recalls.append(recall)

plt.plot(recalls, precisions)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.show()

输出:
在这里插入图片描述

调用sklearnAPI

sklearn已经封装了绘制P-R曲线的函数,使用时只要导入sklearn.metrics.precision_recall_curve就可以了。该函数参数如下:

  • y_true:真实的类标签,默认在 {-1, 1} 或 {0, 1} 中取值
  • pos_label:正类的标签,默认为1
  • probas_pred:样本的预测概率
  • sample_weight:样本权重

函数返回三个列表:

  • precision:不同概率阈值对应的预测准确率
  • recall:不同的概率阈值对应的预测召回率
  • thresholds:绘制P-R曲线时取的不同的概率阈值

我们还是以sklearn.datasets中的乳腺癌数据集为例,在这个数据集上建立一个逻辑回归模型,并绘制该模型的P-R曲线:

from sklearn.metrics import precision_recall_curve
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt

data = load_breast_cancer()
X = data.data
y = data.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=66)

model = LogisticRegression(solver='liblinear')
model.fit(X_train, y_train)
scores = model.decision_function(X_test)

precisions, recalls, thresholds = precision_recall_curve(y_test, scores)

plt.plot(precisions, recalls)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.show()

输出:
在这里插入图片描述

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值