在Python中计算分类报告和混淆矩阵
在本文中,我们将了解如何在Python中计算大小为 3*3 的分类报告和混淆矩阵。
混淆矩阵和分类报告,这两个是 scikit learn 库中非常常用和重要的库函数。但是有多少用户能够真正从零开始实现这两个功能呢?这就是问题所在。只有 40% 的机器学习爱好者能够做到这一点。许多人甚至不知道这些背后的理论。在本文中,我们将从头开始实现这两个函数,并将使用库函数来比较结果。
问题陈述
给定 .csv 格式的 iris 数据集。我们的目标是在不使用Python库函数的情况下对花卉种类进行分类并从头开始开发混淆矩阵和分类报告。此外,将临时函数的结果与标准库函数进行比较。
鸢尾花数据集是多类数据集。数据集中有 5 列。前四列代表花种的属性:花瓣长度、花瓣宽度、萼片长度和萼片宽度。最后一列告诉花的类别标签。花种有 3 种不同的类别:Virginica、Setosa 和 Versicolor。
混淆矩阵的例子:
Input: y_true = {2, 0, 2, 2, 0, 1}
y_pred = {0, 0, 2, 2, 0, 2}
Output: confusion_matrix:
{
{2, 0, 0},
{0, 0, 1},
{1, 0, 2}
}
Explanation:
- Row indicates the actual values of data and columns indicate the predicted data.
- There are three labels i.e. 0, 1 and 2.
- Actual data of label 0 is predicted as: 2, 0, 0; 2 points are predicted as class-0, 0 points as class-1, 0 points as class-2.
- 2nd row {0, 0, 1} tells that: 0 points of class-1 are predicted as class-0 and class-1. 1 point of class-1 is predicted as class-2.
- 3rd row {1, 0, 2}:
- 1 point of class-2 is predicted to class-0.
- 0 point of class-2 is predicted to class-1.
- 2 points of class-2 are predicted to class-2.
Input: y_true = [“cat”, “ant”, “cat”, “cat”, “ant”, “bird”]
y_pred = [“ant”, “ant”, “cat”, “cat”, “ant”, “cat”]
Output: confusion_matrix(y_true, y_pred, labels=[“ant”, “bird”, “cat”])
{ ant bird cat
‘ant’= {2, 0, 0},
‘bird’= {0, 0, 1},
‘cat’= {1, 0, 2}}
Explanation:
- There are 2 ants in actual data-set. Out of total, 2 are predicted as ant, 0 are predicted as bird and cat.
- There are 1 bird in actual dataset. Out of that, 0 are predicted as ant and bird. 1 is predicted as cat.
- There are 3 cats in actual dataset. Out of that, 1 is predicted as ant, 2 are predicted as cat.
什么是分类报告?
顾名思义,这份报告解释了有关分类的一切。这是构建的 ML 模型对分类质量的总结。它主要包括 5 列和 (N+3) 行。第一列是类标签的名称,然后是 Precision、Recall、F1-score 和 Support。 N 行用于 N 类标签,其他三行用于准确度、宏观平均和加权平均。
精度:根据预测值计算。对于 A 类,在总的预测中有多少在实际数据集中真正属于 A 类,被定义为精度。它是混淆矩阵的 [i][i] 单元格与 [i] 列之和的比率。
召回:它是根据数据集中的实际值计算的。对于 A 类,在数据集中的总条目中,有多少被 ML 模型实际分类为 A 类,被定义为召回率。它是混淆矩阵的[i][i]个单元格与[i]行之和的比值。
F1-score:准确率和召回率的调和平均值。
支持度:是实际数据集中每个类的总条目。它只是每个 i 类的行的总和。
分类报告示例:
Input: confusion[][]= {
{1, 0, 0},
{1, 0, 0},
{0, 1, 2}
};
Output:
precision recall f1-score support
class 0 0.50 1.00 0.67 1
class 1 0.00 0.00 0.00 1
class 2 1.00 0.67 0.80 3
accuracy 0.60 5
macro avg 0.50 0.56 0.49 5
weighted avg 0.70 0.60 0.61 5
Input confusion [][]= {
{0, 1},
{0, 2}
};
Output:
precision recall f1-score support
1 1.00 0.67 0.80 3
2 0.00 0.00 0.00 0
3 0.00 0.00 0.00 0
accuracy 0.67
macro avg 0.33 0.22 0.27 3
weighted avg 1.00 0.67 0.80 3
下面是代码实现
Python3
# Our aim is to build the function
# for calculating the confusion_matrix
# and classification_report
# for multiclass classification, like IRIS dataset.
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import classification_report
# Function for confusion matrix
def Confusion_matrix(y_test, y_pred, target_names=None):
# target_names is a list.
# actual values are arranged in the rows.
# predicted values are arranged in the columns.
# if there are m classes, then cm is m*m matrix.
if target_names == None:
m = len(set(y_test))
else:
m = len(target_names)
size = len(y_test)
matrix = dict()
# create matrix initialised with 0
for class_name in range(m):
matrix[class_name] = [0 for k in range(m)]
# populating the matrix.
for i in range(size):
actual_class = y_test[i]
pred_class = y_pred[i]
matrix[actual_class][pred_class] += 1
# Change the name of columns.
if target_names == None:
# Now, lets print the confusion matrix.
print("Confusion Matrix of given model is :")
if m == 3:
print("Count=%-14d %-15s %-15s %-15s" % (size,
'0', '1',
'2'))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d %-15d" %
(key, value[0], value[1], value[2]))
elif m == 2:
print("Count=%-14d %-15s %-15s" % (size, '0', '1'))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d" % (key, value[0],
value[1]))
else:
matrix = dict(zip(target_names, list(matrix.values())))
# Now, lets print the confusion matrix.
print("Confusion Matrix of given model is :")
print("Count=%-14d %-15s %-15s %-15s" %
(size, target_names[0], target_names[1], target_names[2]))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d %-15d" %
(key, value[0], value[1], value[2]))
return matrix
# Function for performance report.
def performance_report(cm):
col = len(cm)
# col=number of class
arr = []
for key, value in cm.items():
arr.append(value)
cr = dict()
support_sum = 0
# macro avg of support is
# sum of support only, not the mean.
macro = [0]*3
# weighted avg of support is
# sum of support only, not the mean.
weighted = [0]*3
for i in range(col):
vertical_sum= sum([arr[j][i] for j in range(col)])
horizontal_sum= sum(arr[i])
p = arr[i][i] / vertical_sum
r = arr[i][i] / horizontal_sum
f = (2 * p * r) / (p + r)
s = horizontal_sum
row=[p,r,f,s]
support_sum+=s
for j in range(3):
macro[j]+=row[j]
weighted[j]+=row[j]*s
cr[i]=row
# add Accuracy parameters.
truepos=0
total=0
for i in range(col):
truepos+=arr[i][i]
total+=sum(arr[i])
cr['Accuracy']=["", "", truepos/total, support_sum]
# Add macro-weight and weighted_avg features.
macro_avg=[Sum/col for Sum in macro]
macro_avg.append(support_sum)
cr['Macro_avg']=macro_avg
weighted_avg=[Sum/support_sum for Sum in weighted]
weighted_avg.append(support_sum)
cr['Weighted_avg']=weighted_avg
# print the classification_report
print("Performance report of the model is :")
space,p,r,f,s=" ","Precision","Recall","F1-Score","Support"
print("%13s %9s %9s %9s %9s\n"%(space,p,r,f,s))
stop=0
for key,value in cr.items():
if stop
输出:
时间复杂度: O(N*N)
空间复杂度: (N*4),对于每个标签,我们需要一个大小为 4 的数组。