一、说明
二、混淆矩阵的基本概念
2.1 连续数据分布
LET将数据视为连续的,分类的或有序的(分类的,但有顺序的)。混淆矩阵是评估分类模型性能的一种方法。对于它如何工作的上下文,我们将首先刷新有关连续数据的知识。通过这个,我们可以看到混淆矩阵只是我们已经知道的直方图的扩展。
当我们想要了解连续数据时,第一步通常是查看它是如何分布的。请考虑以下直方图。
我们可以看到,标签平均约为零,大多数数据点介于 -1 和 1 之间。它看起来是对称的;有一个比平均值小和大的数字的近似偶数。如果我们愿意,我们可以使用表格而不是直方图,但它可能很笨拙。
2.2 分类数据分布
在某些方面,分类数据与连续数据没有太大区别。我们仍然可以生成直方图来评估每个标签的值出现的频率。例如,二进制标签(真/假)的出现频率可能如下所示:
这告诉我们,有 750 个样本以 false 作为标签,250 个样本以 true 作为标签。
三个类别的标签类似:
这告诉我们有 200 个样本是人,400 个是动物,100 个是树。
由于分类标签更简单,我们通常可以将它们显示为简单的表。前面的两个图如下所示:
Label False True
Count 750 250
和
Label Person Animal Tree
Count 200 400 100
2.3 查看预测
我们可以查看模型做出的预测,就像查看数据中的真实标签一样。例如,我们可能会看到,在测试集中,我们的模型预测了 700 次错误和 300 次 true。
Prediction Count
False 700
True 300
这提供了有关我们的模型所做的预测的直接信息,但它并没有告诉我们哪些是正确的。虽然我们可以使用成本函数来了解给出正确响应的频率,但成本函数不会告诉我们犯了哪种错误。
例如,模型可能正确猜测所有真值,但在应该猜到假时也会猜测真。
2.4 混淆矩阵
了解模型性能的关键是将模型预测表与真实数据标签表组合在一起:
我们尚未填写的方块称为混淆矩阵。
混淆矩阵中的每个单元格都告诉我们有关模型性能的一件事。这些是真阴性 (TN)、假阴性 (FN)、
假阳性 (FP) 和真阳性 (TP)。
让我们一一解释这些,将这些首字母缩略词替换为实际值。蓝绿色方块表示模型做出了正确的预测,橙色方块表示模型做出了错误的预测。
2.5 真阴性 (TN)
左上角的值将列出模型预测为假的次数,实际标签也是假的。换句话说,这列出了模型正确预测错误的次数。假设,对于我们的示例,这种情况发生了 500 次:
2.6 漏报 (FN)
右上角的值告诉我们模型预测为假的次数,但实际标签为真。我们现在知道这是200。如何?因为模型预测错误了 700 次,其中 500 次它正确地预测了。因此,它必须预测200次,而它不应该预测错误。
2.7 False Positives (FP)
左下角的值包含误报。这告诉我们模型预测为真的次数,但实际标签是假的。我们现在知道这是250,因为有750次正确答案是错误的。其中 500 次显示在左上角单元格 (TN) 中:
2.8 真阳性 (TP)
最后,我们有真正的积极因素。这是模型正确预测 true 的次数。我们知道这是50,原因有两个。首先,模型预测了 300 次为真,但 250 次不正确(左下角单元格)。其次,有250次是真答案,但模型预测是假的200次。
2.9 最终混淆矩阵
我们通常会稍微简化我们的混淆矩阵,如下所示:
我们在此处对单元格进行了着色,以突出显示模型何时做出正确的预测。由此,我们不仅知道模型做出某些类型预测的频率,还知道这些预测正确或不正确的频率。
当有更多标签时,也可以构造混淆矩阵。例如,对于我们的人/动物/树的例子,我们可能会得到一个矩阵,如下所示:
当有三个类别时,像真阳性这样的指标不再适用,但我们仍然可以准确地看到模型犯某些类型错误的频率。例如,我们可以看到,当实际正确结果是动物时,模型预测了该人 200 次。
在本练习中,我们将更详细地使用不平衡数据集、准确性和混淆矩阵的概念来衡量分类模型的性能。
三、数据可视化
我们的新数据集代表了在雪中发现的不同类别的物体。让我们通过加载并查看我们的数据来开始这个练习:
import pandas
!wget https://raw.githubusercontent.com/MicrosoftDocs/mslearn-introduction-to-machine-learning/main/graphing.py
!wget https://raw.githubusercontent.com/MicrosoftDocs/mslearn-introduction-to-machine-learning/main/Data/snow_objects.csv
#Import the data from the .csv file
dataset = pandas.read_csv('snow_objects.csv', delimiter="\t")
#Let's have a look at the data
dataset
size roughness color motion label
0 50.959361 1.318226 green 0.054290 tree
1 60.008521 0.554291 brown 0.000000 tree
2 20.530772 1.097752 white 1.380464 tree
3 28.092138 0.966482 grey 0.650528 tree
4 48.344211 0.799093 grey 0.000000 tree
... ... ... ... ... ...
2195 1.918175 1.182234 white 0.000000 animal
2196 1.000694 1.332152 black 4.041097 animal
2197 2.331485 0.734561 brown 0.961486 animal
2198 1.786560 0.707935 black 0.000000 animal
2199 1.518813 1.447957 brown 0.000000 animal
2200 rows × 5 columns
四、数据探索
我们可以看到数据集既有连续数据(大小、粗糙度、运动),也有分类数据(颜色和标签)。让我们进行一些快速的数据探索,看看我们有哪些不同的标签分类及其各自的计数:
import graphing # custom graphing code. See our GitHub repo for details
# Plot a histogram with counts for each label
graphing.multiple_histogram(dataset, label_x="label", label_group="label", title="Label distribution")
前面的直方图使我们很容易理解数据集中的标签及其分布。
需要注意的一个重要信息是,这是一个数据集不平衡:类别的比例不同(例如,我们的岩石和树木是动物的 4 倍)。这是相关的,因为不平衡的集合在“野外”非常常见。将来,我们将学习如何解决这个问题以构建更好的模型。
我们可以对颜色特征进行相同的分析:
# Plot a histogram with counts for each label
graphing.multiple_histogram(dataset, label_x="color", label_group="color", title="Color distribution")
我们可以注意到:
- 我们有 8 种不同的颜色类别。
- 颜色特征也严重不平衡。
- 绘图算法不够智能,无法为各自的名称分配正确的颜色。
让我们看看我们可以找到有关其他功能的内容:
graphing.box_and_whisker(dataset, label_y="size", title='Boxplot of "size" feature')
在前面的箱图中,我们注意到大多数样本相对较小,大小范围从 0 到 70,但我们有一些更大的异常值。
让我们绘制粗糙度特征:
graphing.box_and_whisker(dataset, label_y="roughness", title='Boxplot of "roughness" feature')
这里没有太多变化:粗糙度值的范围从 0 到略高于 2,大多数样本的值接近平均值。
让我们绘制运动特征:
graphing.box_and_whisker(dataset, label_y="motion", title='Boxplot of "motion" feature')
大多数物体似乎要么是静止的,要么移动得非常缓慢。移动速度较快的对象数量较少,有几个异常值超过 10。
从前面的数据中,人们可以假设更小、更快的物体可能是徒步旅行者和动物,而更大、更静态的元素是树木和岩石。
五、构建分类模型
让我们使用随机森林构建和训练一个分类模型,以根据数据集中的特征预测对象的类别:
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
# Split the dataset in an 70/30 train/test ratio.
train, test = train_test_split(dataset, test_size=0.3, random_state=2)
print(train.shape)
print(test.shape)
(1540, 5)
(660, 5)
现在,我们可以使用刚刚创建的训练数据集来训练模型:
# Create the model
model = RandomForestClassifier(n_estimators=1, random_state=1, verbose=False)
# Define which features are to be used (leave color out for now)
features = ["size", "roughness", "motion"]
# Train the model
model.fit(train[features], train.label)
print("Model trained!")
Model trained!
六、评估模型
现在,我们可以使用新训练的模型来使用测试集进行预测。通过将预测值与实际标签(也称为 true 值)进行比较,我们可以使用不同的指标来衡量模型的性能。
例如,准确度是执行的所有预测中正确预测的标签数:
Accuracy = Correct Predictions / Total Predictions
让我们看看如何在代码中完成此操作:
# Import a function that measures a models accuracy
from sklearn.metrics import accuracy_score
# Calculate the model's accuracy on the TEST set
actual = test.label
predictions = model.predict(test[features])
# Return accuracy as a fraction
acc = accuracy_score(actual, predictions)
# Return accuracy as a number of correct predictions
acc_norm = accuracy_score(actual, predictions, normalize=False)
print(f"The random forest model's accuracy on the test set is {acc:.4f}.")
print(f"It correctly predicted {acc_norm} labels in {len(test.label)} predictions.")
The random forest model's accuracy on the test set is 0.8924.
It correctly predicted 589 labels in 660 predictions.
我们的模型似乎做得很好!
然而,这种直觉可能会产生误导:
- 准确性不考虑模型做出的错误预测。
- 它也不擅长在类不平衡的数据集中描绘清晰的画面,比如我们的数据集,其中可能的类的数量分布不均匀(回想一下,我们有 800 棵树,800 块岩石,但只有 200 只动物)。
七、构建混淆矩阵
混淆矩阵是一个表格,我们将实际标签与模型预测的内容进行比较。它让我们更详细地了解模型是如何工作的,以及它在哪里做对或缺失。
这是我们可以在代码中执行此操作的方法之一:
# sklearn has a very convenient utility to build confusion matrices
from sklearn.metrics import confusion_matrix
# Build and print our confusion matrix, using the actual values and predictions
# from the test set, calculated in previous cells
cm = confusion_matrix(actual, predictions, normalize=None)
print("Confusion matrix for the test set:")
print(cm)
Confusion matrix for the test set:
[[ 28 38 0 0]
[ 30 103 1 0]
[ 0 1 217 1]
[ 0 0 0 241]]
虽然前面的矩阵在计算中很有用,但它不是很有帮助或直观。让我们添加一个带有标签和颜色的绘图,以将该数据转化为实际见解:
# We use plotly to create plots and charts
import plotly.figure_factory as ff
# Create the list of unique labels in the test set, to use in our plot
# I.e., ['animal', 'hiker', 'rock', 'tree']
x = y = sorted(list(test["label"].unique()))
# Plot the matrix above as a heatmap with annotations (values) in its cells
fig = ff.create_annotated_heatmap(cm, x, y)
# Set titles and ordering
fig.update_layout( title_text="<b>Confusion matrix</b>",
yaxis = dict(categoryorder = "category descending"))
fig.add_annotation(dict(font=dict(color="black",size=14),
x=0.5,
y=-0.15,
showarrow=False,
text="Predicted label",
xref="paper",
yref="paper"))
fig.add_annotation(dict(font=dict(color="black",size=14),
x=-0.15,
y=0.5,
showarrow=False,
text="Actual label",
textangle=-90,
xref="paper",
yref="paper"))
# We need margins so the titles fit
fig.update_layout(margin=dict(t=80, r=20, l=100, b=50))
fig['data'][0]['showscale'] = True
fig.show()
请注意,该图在 y 轴上具有“实际标签”,在 x 轴上具有“预测”标签,如confusion_matrix函数调用所定义。
我们可以看到该模型通常是准确的,但这只是因为我们的集合中有如此多的岩石和树木,并且因为它在这些类上表现良好。
当涉及到徒步旅行者和动物时,模型会感到困惑(它显示了大量的FP和FN),但由于这些类在数据集中的代表性较少,因此准确性分数仍然很高。
八、总结
在本练习中,我们讨论了以下概念:
- 不平衡数据集,其中要素或类可能由不成比例的样本表示。
- 准确性作为评估模型性能及其缺点的指标。
- 如何生成、绘制和解释混淆矩阵,以更好地了解分类模型的性能。
-
V笔记本
祝你学习愉快!
下一>> 混淆矩阵和数据不平衡 (2/3)