Scikit 学习如何打印混淆矩阵的标签?
Posted
技术标签:
【中文标题】Scikit 学习如何打印混淆矩阵的标签?【英文标题】:Sci-kit learn how to print labels for confusion matrix? 【发布时间】:2018-10-23 20:18:36 【问题描述】:所以我正在使用 sci-kit learn 对一些数据进行分类。我有 13 个不同的类值/分类来对数据进行分类。现在我已经能够使用交叉验证并打印混淆矩阵了。但是,它只显示没有类标签的 TP 和 FP 等,所以我不知道哪个类是什么。以下是我的代码和输出:
def classify_data(df, feature_cols, file):
nbr_folds = 5
RANDOM_STATE = 0
attributes = df.loc[:, feature_cols] # Also known as x
class_label = df['task'] # Class label, also known as y.
file.write("\nFeatures used: ")
for feature in feature_cols:
file.write(feature + ",")
print("Features used", feature_cols)
sampler = RandomOverSampler(random_state=RANDOM_STATE)
print("RandomForest")
file.write("\nRandomForest")
rfc = RandomForestClassifier(max_depth=2, random_state=RANDOM_STATE)
pipeline = make_pipeline(sampler, rfc)
class_label_predicted = cross_val_predict(pipeline, attributes, class_label, cv=nbr_folds)
conf_mat = confusion_matrix(class_label, class_label_predicted)
print(conf_mat)
accuracy = accuracy_score(class_label, class_label_predicted)
print("Rows classified: " + str(len(class_label_predicted)))
print("Accuracy: 0:.3f%\n".format(accuracy * 100))
file.write("\nClassifier settings:" + str(pipeline) + "\n")
file.write("\nRows classified: " + str(len(class_label_predicted)))
file.write("\nAccuracy: 0:.3f%\n".format(accuracy * 100))
file.writelines('\t'.join(str(j) for j in i) + '\n' for i in conf_mat)
#Output
Rows classified: 23504
Accuracy: 17.925%
0 372 46 88 5 73 0 536 44 317 0 200 127
0 501 29 85 0 136 0 655 9 154 0 172 67
0 97 141 78 1 56 0 336 37 429 0 435 198
0 135 74 416 5 37 0 507 19 323 0 128 164
0 247 72 145 12 64 0 424 21 296 0 304 223
0 190 41 36 0 178 0 984 29 196 0 111 43
0 218 13 71 7 52 0 917 139 177 0 111 103
0 215 30 84 3 71 0 1175 11 55 0 102 62
0 257 55 156 1 13 0 322 184 463 0 197 160
0 188 36 104 2 34 0 313 99 827 0 69 136
0 281 80 111 22 16 0 494 19 261 0 313 211
0 207 66 87 18 58 0 489 23 157 0 464 239
0 113 114 44 6 51 0 389 30 408 0 338 315
如您所见,您无法真正知道哪一列是什么,而且打印也“未对齐”,因此很难理解。
还有打印标签的方法吗?
【问题讨论】:
【参考方案1】:从doc看来,似乎没有打印混淆矩阵的行列标签的选项。但是,您可以使用参数 labels=...
例子:
from sklearn.metrics import confusion_matrix
y_true = ['yes','yes','yes','no','no','no']
y_pred = ['yes','no','no','no','no','no']
print(confusion_matrix(y_true, y_pred))
# Output:
# [[3 0]
# [2 1]]
print(confusion_matrix(y_true, y_pred, labels=['yes', 'no']))
# Output:
# [[1 2]
# [0 3]]
如果您想打印带有标签的混淆矩阵,您可以尝试pandas
并设置DataFrame
的index
和columns
。
import pandas as pd
cmtx = pd.DataFrame(
confusion_matrix(y_true, y_pred, labels=['yes', 'no']),
index=['true:yes', 'true:no'],
columns=['pred:yes', 'pred:no']
)
print(cmtx)
# Output:
# pred:yes pred:no
# true:yes 1 2
# true:no 0 3
或者
unique_label = np.unique([y_true, y_pred])
cmtx = pd.DataFrame(
confusion_matrix(y_true, y_pred, labels=unique_label),
index=['true::'.format(x) for x in unique_label],
columns=['pred::'.format(x) for x in unique_label]
)
print(cmtx)
# Output:
# pred:no pred:yes
# true:no 3 0
# true:yes 2 1
【讨论】:
如果我的算法学习的是整个事物的一个子集怎么办?然后不是所有这些都被猜到了吗?这将导致添加没有 y_pred 值和错误形状的标签。 @VaidøtasIvøška 我的最后一个示例是否通过使用y_true[subset]
和y_pred[subset]
解决了您的问题?
我明白你的意思。我没有通读它(只看ex.1),但我设法自己解决了我的问题,因为我认识到我需要一个来自“已知真实”和“在测试期间预测”的唯一值列表'。如果您不介意,我将发布我自己的答案。【参考方案2】:
确保标记混淆矩阵行和列的方式与 sklearn 对类的编码方式完全一致,这一点很重要。标签的真实顺序可以使用分类器的 .classes_ 属性来显示。您可以使用下面的代码来准备混淆矩阵数据框。
labels = rfc.classes_
conf_df = pd.DataFrame(confusion_matrix(class_label, class_label_predicted, columns=labels, index=labels))
conf_df.index.name = 'True labels'
要注意的第二件事是您的分类器不能很好地预测标签。正确预测的标签数量显示在混淆矩阵的主对角线上。您在矩阵中具有非零值,并且根本没有预测某些类 - 列全为零。使用默认参数运行分类器然后尝试优化它们可能是个好主意。
【讨论】:
【参考方案3】:另一种更好的方法是在 pandas 中使用交叉表函数。
pd.crosstab(y_true, y_pred, rownames=['True'], colnames=['Predicted'], margins=True)
或
pd.crosstab(le.inverse_transform(y_true),
le.inverse_transform(y_pred),
rownames=['True'],
colnames=['Predicted'],
margins=True)
【讨论】:
绝对是最干净的答案!【参考方案4】:由于混淆矩阵只是一个numpy矩阵,它不包含任何列信息。您可以做的是将矩阵转换为数据框,然后打印此数据框。
import pandas as pd
import numpy as np
def cm2df(cm, labels):
df = pd.DataFrame()
# rows
for i, row_label in enumerate(labels):
rowdata=
# columns
for j, col_label in enumerate(labels):
rowdata[col_label]=cm[i,j]
df = df.append(pd.DataFrame.from_dict(row_label:rowdata, orient='index'))
return df[labels]
cm = np.arange(9).reshape((3, 3))
df = cm2df(cm, ["a", "b", "c"])
print(df)
代码 sn-p 来自https://gist.github.com/nickynicolson/202fe765c99af49acb20ea9f77b6255e
输出:
a b c
a 0 1 2
b 3 4 5
c 6 7 8
【讨论】:
【参考方案5】:您的数据似乎有 13 个不同的类别,这就是为什么您的混淆矩阵有 13 行和 13 列的原因。此外,您的类没有以任何方式标记,只是我所看到的整数。
如果不是这种情况,并且您的训练数据有实际标签,您可以将唯一标签列表传递给confusion_matrix
conf_mat = confusion_matrix(class_label, class_label_predicted, df['task'].unique())
【讨论】:
我的数据被标记了。我有一个名为“任务”的列,然后每一行都有一个值,例如 t1、t2、t3 等等。我会试试你的建议。 嗯,我得到了这个 'numpy.ndarray' 对象没有属性 'unique'以上是关于Scikit 学习如何打印混淆矩阵的标签?的主要内容,如果未能解决你的问题,请参考以下文章