AP定义
AP 就是Precision-recall 曲线下面的面积,通常来说一个越好的分类器,AP值越高
计算平均精度(Average Precision)的Python库函数介绍
sklearn.metrics.average_precision_score
是一个用于计算平均精度(AP)的函数,它用于评估二分类或多分类模型的性能。平均精度是根据预测分数来总结精确率-召回率曲线的指标,它衡量了模型在不同召回率下的平均精确率。这个函数计算了各种阈值下的精确率,并以召回率的增加作为权重来计算加权平均精度。
py
sklearn.metrics.average_precision_score(y_true, y_score, *, average='macro', pos_label=1, sample_weight=None)
参数说明
y_true
:真实的二元标签或二元标签指示器。y_score
:目标分数,可以是正类别的概率估计、置信度值或者一些分类器的非阈值化的决策度量。average
:用于确定对数据执行的平均类型。可以是 'micro'、'macro'、'weighted'、'samples' 或者 None。它决定了在数据上执行的平均类型。pos_label
:正类别的标签。仅适用于二元y_true
。对于多标签指示器y_true
,pos_label
固定为 1。sample_weight
:样本权重。
返回值
average_precision
:平均精度分数。
示例
ini
pythonCopy code
import numpy as np
from sklearn.metrics import average_precision_score
# 示例 1
y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])
ap_score_1 = average_precision_score(y_true, y_scores)
print(ap_score_1) # 输出:0.83...
# 示例 2
y_true = np.array([0, 0, 1, 1, 2, 2])
y_scores = np.array([
[0.7, 0.2, 0.1],
[0.4, 0.3, 0.3],
[0.1, 0.8, 0.1],
[0.2, 0.3, 0.5],
[0.4, 0.4, 0.2],
[0.1, 0.2, 0.7],
])
ap_score_2 = average_precision_score(y_true, y_scores)
print(ap_score_2) # 输出:0.77...
精确率-召回率(Precision-Recall)曲线在评估分类器输出质量方面的示例
精确率-召回率是在类别非常不平衡的情况下评估预测成功的一个有用指标。在信息检索中,精确率是结果相关性的度量,而召回率则是返回了多少真正相关的结果的度量。
精确率-召回率曲线展示了在不同阈值下精确率和召回率之间的权衡。曲线下的高面积代表了高召回率和高精确率,高精确率与低误报率相关联,高召回率与低漏报率相关联。高分数表明分类器返回了准确的结果(高精确率),同时返回了大多数所有正例结果(高召回率)。
一个具有高召回率但低精确率的系统会返回许多结果,但与训练标签相比,大多数预测的标签都是错误的。一个具有高精确率但低召回率的系统则恰恰相反,返回的结果很少,但其中大多数预测的标签是与训练标签相匹配的。一个理想的系统具有高精确率和高召回率,将会返回许多结果,其中所有结果都被正确标记。
精确率(Precision) 定义为真正例数目(TP)除以真正例数目与假正例数目(FP)之和:
<math xmlns="http://www.w3.org/1998/Math/MathML"> P r e c i s i o n = T P T P + F P Precision = \frac{TP}{TP+FP} </math>Precision=TP+FPTP
召回率(Recall) 定义为真正例数目(TP)除以真正例数目与假负例数目(FN)之和:
<math xmlns="http://www.w3.org/1998/Math/MathML"> R e c a l l = T P T P + F B Recall= \frac{TP}{TP + FB} </math>Recall=TP+FBTP
这些量也与 F1 分数 相关联,F1 分数定义为精确率和召回率的调和平均数。
注意精确率可能不随着召回率降低而降低。精确率的定义表明,降低分类器的阈值可能会增加分母,即增加返回的结果数目。如果阈值先前设置得过高,新结果可能全部是真正例,这将增加精确率。如果之前的阈值大致合适或者太低,进一步降低阈值将引入假正例,降低精确率。
召回率不依赖于分类器的阈值。这意味着降低分类器的阈值可能会增加召回率,通过增加真正例的结果数目。降低阈值也可能保持召回率不变,而精确率波动。
召回率和精确率之间的关系可以在绘图中观察到的阶梯区域中。在这些步骤的边缘,阈值的微小变化会显著降低精确率,而召回率略微增加。
平均精确率(AP) 总结了这样一个曲线,它是在每个阈值下取得的精确率的加权平均数,其中从前一个阈值增加的召回率用作权重:
<math xmlns="http://www.w3.org/1998/Math/MathML"> A P = ∑ n ( R n − R n − 1 ) P n AP=∑n(Rn−Rn−1)Pn </math>AP=∑n(Rn−Rn−1)Pn
这里 <math xmlns="http://www.w3.org/1998/Math/MathML"> P n 和 R n 是第 n 个阈值时的精确率和召回率。一对 , P , R P_n 和 R_n 是第 n 个阈值时的精确率和召回率。一对 ,P,R </math>Pn和Rn是第n个阈值时的精确率和召回率。一对,P,R被称为一个操作点。
AP 和操作点下的梯形面积(sklearn.metrics.auc)是总结精确率-召回率曲线的常见方式,会得到不同的结果。更多详情请阅读用户指南。
精确率-召回率曲线通常用于二元分类以研究分类器的输出。为了将精确率-召回率曲线和平均精确率扩展到多类别或多标签分类,需要将输出进行二值化。可以为每个标签绘制一条曲线,也可以通过将标签指示矩阵的每个元素视为二进制预测来绘制精确率-召回率曲线(微平均)。
注意
- 查看也有:sklearn.metrics.average_precision_score、sklearn.metrics.recall_score、sklearn.metrics.precision_score、sklearn.metrics.f1_score
二元分类设置
数据集和模型
我们将使用 Linear SVC 分类器来区分两种类型的鸢尾花。
ini
pythonCopy code
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
X, y = load_iris(return_X_y=True)
# 添加噪声特征
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
X = np.concatenate([X, random_state.randn(n_samples, 200 * n_features)], axis=1)
# 限制为前两个类别,并分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X[y < 2], y[y < 2], test_size=0.5, random_state=random_state
)
Linear SVC 需要每个特征具有类似范围的值。因此,我们将首先使用 StandardScaler 对数据进行缩放。
javascript
pythonCopy code
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
classifier = make_pipeline(
StandardScaler(), LinearSVC(random_state=random_state, dual="auto")
)
classifier.fit(X_train, y_train)
Recall 曲线
为了绘制精确率-召回率曲线,您可以使用 PrecisionRecallDisplay
。实际上,有两种可用的方法,具体取决于您是否已经计算了分类器的预测。
让我们首先绘制没有分类器预测的精确率-召回率曲线。我们使用 from_estimator
方法,在绘制曲线之前计算分类器的预测结果。
ini
pythonCopy code
from sklearn.metrics import PrecisionRecallDisplay
display = PrecisionRecallDisplay.from_estimator(
classifier, X_test, y_test, name="LinearSVC", plot_chance_level=True
)
_ = display.ax_.set_title("2-class Precision-Recall curve")
如果我们已经获得了模型的估计概率或得分,那么我们可以使用 from_predictions
方法。
ini
pythonCopy code
y_score = classifier.decision_function(X_test)
display = PrecisionRecallDisplay.from_predictions(
y_test, y_score, name="LinearSVC"
)
_ = display.ax_.set_title("2-class Precision-Recall curve")
多标签设置
精确率-召回率曲线不支持多标签设置。然而,我们可以决定如何处理这种情况。下面我们展示一个示例。
创建多标签数据,拟合和预测
我们创建一个多标签数据集,以展示多标签设置下的精确率-召回率。
ini
pythonCopy code
from sklearn.preprocessing import label_binarize
# 使用 label_binarize 实现多标签设置
Y = label_binarize(y, classes=[0, 1, 2])
n_classes = Y.shape[1]
# 分为训练集和测试集
X_train, X_test, Y_train, Y_test = train_test_split(
X, Y, test_size=0.5, random_state=random_state
)
对于多标签预测,我们使用 OneVsRestClassifier
。
ini
pythonCopy code
from sklearn.multiclass import OneVsRestClassifier
classifier = OneVsRestClassifier(
make_pipeline(StandardScaler(), LinearSVC(random_state=random_state, dual="auto"))
)
classifier.fit(X_train, Y_train)
y_score = classifier.decision_function(X_test)
多标签设置中的平均精确率分数
ini
pythonCopy code
from sklearn.metrics import average_precision_score, precision_recall_curve
# 对于每个类别
precision = dict()
recall = dict()
average_precision = dict()
for i in range(n_classes):
precision[i], recall[i], _ = precision_recall_curve(Y_test[:, i], y_score[:, i])
average_precision[i] = average_precision_score(Y_test[:, i], y_score[:, i])
# "微平均":对所有类别联合计算分数
precision["micro"], recall["micro"], _ = precision_recall_curve(
Y_test.ravel(), y_score.ravel()
)
average_precision["micro"] = average_precision_score(Y_test, y_score, average="micro")
绘制微平均的精确率-召回率曲线
ini
pythonCopy code
from collections import Counter
display = PrecisionRecallDisplay(
recall=recall["micro"],
precision=precision["micro"],
average_precision=average_precision["micro"],
prevalence_pos_label=Counter(Y_test.ravel())[1] / Y_test.size,
)
display.plot(plot_chance_level=True)
_ = display.ax_.set_title("Micro-averaged over all classes")
绘制每个类别的精确率-召回率曲线和 iso-f1 曲线
css
pythonCopy code
from itertools import cycle
import matplotlib.pyplot as plt
# 设置绘图细节
colors = cycle(["navy", "turquoise", "darkorange", "cornflowerblue", "teal"])
_, ax = plt.subplots(figsize=(7, 8))
f_scores = np.linspace(0.2, 0.8, num=4)
lines, labels = [], []
for f_score in f_scores:
x = np.linspace(0.01, 1)
y = f_score * x / (2 * x - f_score)
(l,) = plt.plot(x[y >= 0], y[y >= 0], color="gray", alpha=0.2)
plt.annotate("f1={0:0.1f}".format(f_score), xy=(0.9, y[45] + 0.02))
display = PrecisionRecallDisplay(
recall=recall["micro"],
precision=precision["micro"],
average_precision=average_precision["micro"],
)
display.plot(ax=ax, name="Micro-average precision-recall", color="gold")
for i, color in zip(range(n_classes), colors):
display = PrecisionRecallDisplay(
recall=recall[i],
precision=precision[i],
average_precision=average_precision[i],
)
display.plot(ax=ax, name=f"Precision-recall for class {i}", color=color)
# 添加 iso-f1 曲线的图例
handles, labels = display.ax_.get_legend_handles_labels()
handles.extend([l])
labels.extend(["iso-f1 curves"])
# 设置图例和坐标轴
ax.set_xlim([0.0, 1.0])
ax.set_ylim([0.0, 1.05])
ax.legend(handles=handles, labels=labels, loc="best")
ax.set_title("Extension of Precision-Recall curve to multi-class")
plt.show()
这些代码片段展示了如何使用 PrecisionRecallDisplay
和其他 sklearn 库函数绘制精确率-召回率曲线,在二元和多标签分类问题中评估分类器的性能。这些可视化方法可以帮助您更好地理解分类器的输出质量,并根据结果作出更明智的决策