6.评估分类模型
训练,调优和建立模型是整个分析生命周期的重要部分,但更重要的是知道这些模型的性能如何。分类模型的性能一般基于模型对新数据的预测输出结果。通常情况下,使用测试数据集或保留数据集对性能进行测量,数据集中的数据不会以任何方式影响或训练分类器。测试数据集一般包括一些观测值和对应的标签。
使用与训练模型时一样的方法提取特征。这些特征被送入训练好的模型,就获得了每个数据的预测结果。接着,预测结果与实际标签进行匹配以观察模型预测结果如何或其精准情况。
有多个指标可以判定模型的预测性能,但将主要关注下面几个指标:
- 准确率(accuracy)。
- 精确率(precision)。
- 召回率(recall)。
- F1 score。
让我们看看实际的例子,看看如何计算这些指标。考虑一个将邮件分类为 “Spam”(垃圾邮件)或 “ham”(正常邮件)之一的二分类问题。假设共有 20 封邮件,对于每封邮件已经有了实际的手工标签,将这些邮件送入已经建好的分类器,就得到了每封邮件的预测标签。现在,想通过比较两个预测值与实际标签来衡量分类器的性能。下面的代码设置初始化依赖项、实际标签与预测的标签。
from
sklearn
import
metrics
import
numpy as np
import
pandas as pd
from
collections
import
Counter
actual_labels
=
[
'spam'
,
'ham'
,
'spam'
,
'spam'
,
'spam'
,
'ham'
,
'ham'
,
'spam'
,
'ham'
,
'spam'
,
'spam'
,
'ham'
,
'ham'
,
'ham'
,
'spam'
,
'ham'
,
'ham'
,
'spam'
,
'spam'
,
'ham'
]
predicted_labels
=
[
'spam'
,
'spam'
,
'spam'
,
'ham'
,
'spam'
,
'spam'
,
'ham'
,
'ham'
,
'spam'
,
'spam'
,
'ham'
,
'ham'
,
'spam'
,
'ham'
,
'ham'
,
'ham'
,
'spam'
,
'ham'
,
'spam'
,
'spam'
]
ac
=
Counter(actual_labels)
pc
=
Counter(predicted_labels)
|
现在,通过下面的代码看看实际标签和预测标签中属于 “span” 或 “ham” 类的邮件总数:
In [
4
]:
print
(
'Actual counts:'
, ac.most_common())
...:
print
(
'Predicted counts:'
, pc.most_common())
Actual counts: [(
'ham'
,
10
), (
'spam'
,
10
)]
Predicted counts: [(
'spam'
,
11
), (
'ham'
,
9
)]
|
因此,看到共有 10 封电子邮件是 “spam” 和 10 封电子邮件是 “ham”。分类器预测共有 11 封邮件是 “spam” 和 9 封邮件是 “ham”。现在如何比较这些电子邮件是真正的 “spam”,它的归类是什么?混淆矩阵是衡量两个类分类性能的很好的方法。混淆矩阵是一个表格结构,它有助于可视化分类器的性能。矩阵中的每一列代表预测的分类示例,矩阵的每一行代表实际分类标签的分类示例(如果需要的话,也可将其反转)。通常定义一个类标签为正类,这是我们感兴趣的类。下表给出了典型的两类分类混淆矩阵,其中 p 代表正类,n 代表反类。
|
p' (预测) |
n‘ (预测) |
---|---|---|
p (实际) |
真阳性 | 假阳性 |
n (实际) |
假阳性 | 真阳性 |
上表中,可以看到矩阵中的一些术语。真阳性(TP)表示正确的命中数或预测为正类。假阴性(FN)表示错误地讲这个类的示例预测为错误的负类。假阳性(FP)是错误地预测为正类时,实际上它不是。真阴性(TN)是正确预测为负类的实例数。
下面的代码为我们的数据简历了一个混淆矩阵:
In [
7
]: cm
=
metrics.confusion_matrix(y_true
=
actual_labels,
...: y_pred
=
predicted_labels,
...: labels
=
[
'spam'
,
'ham'
])
...:
In [
8
]:
print
(pd.DataFrame(
...: data
=
cm,
...: columns
=
pd.MultiIndex(levels
=
[[
'Predicted:'
],
...: [
'spam'
,
'ham'
]],
...: labels
=
[[
0
,
0
],[
0
,
1
]]),
...: index
=
pd.MultiIndex(levels
=
[[
'Actual:'
],
...: [
'spam'
,
'ham'
]],
...: labels
=
[[
0
,
0
],[
0
,
1
]])))
...:
Predicted:
spam ham
Actual: spam
5
5
ham
6
4
|
现在得到一个与上图图片中类似的混淆矩阵。假设 spam“ 是正类”。现在可以在下面的代码段中定义前面的指标:
positive_class
=
'spam'
true_positive
=
5.
false_positive
=
6.
false_negative
=
5.
true_negative
=
4.
|
既然从混淆矩阵中得到了必要的值,就可以逐一计算四个性能指标。为了有助于除法计算,把这些值作为浮点数。将使用 scikit-learn 的指标(metriss)模块,该模块非常强大,有助于在一个函数内计算这些指标。将手动定义和计算这些指标,以便你可以清楚了解它们,并从 metriss 模块中看到这些函数的内部执行情况。
准确率定义为模型整体的准确性或正确预测的比例,可由下面的公式表示:
这里在分子和分母中使用正确预测数量除以全部输出数量。下面的代码给出了准确率的计算:
In [
10
]: accuracy
=
np.
round
(
...: metrics.accuracy_score(y_true
=
actual_labels,
...: y_pred
=
predicted_labels),
2
)
...: accuracy_manual
=
np.
round
(
...: (true_positive
+
true_negative)
/
...: (true_positive
+
true_negative
+
...: false_negative
+
false_positive),
2
)
...:
print
(
'Accuracy:'
, accuracy)
...:
print
(
'Manually computed accuracy:'
, accuracy_manual)
...:
Accuracy:
0.45
Manually computed accuracy:
0.45
|
精确率定义为正类准确预测的数量与正类相关所有预测的比值,可用公式描述为:
这里使用正类正确预测的数量除以正类的所有预测数量,包括预测为假阳性的数量。下面的代码给出了精确率的计算:
In [
11
]: precision
=
np.
round
(
...: metrics.precision_score(y_true
=
actual_labels,
...: y_pred
=
predicted_labels,
...: pos_label
=
positive_class),
2
)
...: precision_manual
=
np.
round
(
...: (true_positive)
/
...: (true_positive
+
false_positive),
2
)
...:
print
(
'Precision:'
, precision)
...:
print
(
'Manually computed precision:'
, precision_manual)
...:
Precision:
0.45
Manually computed precision:
0.45
|
召回率的定义是正类中被正确预测的实例数,也称之为命中率、覆盖率或灵敏率,可用公式描述为:
其中,使用正则中正确预测的数量除以正确与未正确预测的数量之和,得到命中率。以下代码给出召回率的计算:
In [
12
]: recall
=
np.
round
(
...: metrics.recall_score(y_true
=
actual_labels,
...: y_pred
=
predicted_labels,
...: pos_label
=
positive_class),
2
)
...: recall_manual
=
np.
round
(
...: (true_positive)
/
...: (true_positive
+
false_negative),
2
)
...:
print
(
'Recall:'
, recall)
...:
print
(
'Manually computed recall:'
, recall_manual)
...:
Recall:
0.5
Manually computed recall:
0.5
|
F1 score 是另一个标准性指标,通过计算精确率和召回率的调和平均值得到,其用公式表示如下:
可以使用下面的代码计算一样的 F1 score:
In [
13
]: f1_score
=
np.
round
(
...: metrics.f1_score(y_true
=
actual_labels,
...: y_pred
=
predicted_labels,
...: pos_label
=
positive_class),
2
)
...: f1_score_manual
=
np.
round
(
...: (
2
*
precision
*
recall)
/
...: (precision
+
recall),
2
)
...:
print
(
'F1 score:'
, f1_score)
...:
print
(
'Manually computed F1 score:'
, f1_score_manual)
...:
F1 score:
0.48
Manually computed F1 score:
0.47
|
这里给出了几个评估分类模型最常用的主要指标,将用来苹果模型的性能的正式以上指标。