Sci-kit learn如何打印混淆矩阵的标签?

18

我正在使用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

正如您所看到的,您无法真正知道哪一列是什么,打印的内容也“不对齐”,因此很难理解。

有没有办法同时打印标签呢?

5个回答

31
文档中看来,似乎没有选项可以打印混淆矩阵的行和列标签。然而,您可以使用参数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 并设置 DataFrameindexcolumns

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øtas I.
@VaidøtasIvøška,我的最后一个示例是否通过使用y_true [subset]y_pred [subset]解决了您的问题? - pe-perry
我明白你的意思。我没有完全阅读它(只看了例子1),但是我通过认识到我需要一个从“已知真实”和“测试期间预测”的唯一值列表来解决自己的问题。如果您不介意,我将发布自己的答案。 - Vaidøtas I.

5

确保你标记混淆矩阵的行和列的方式与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中的交叉表(crosstab)函数。

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)

1
绝对是最干净的答案! - Mohammad-Reza Malekpour

1

由于混淆矩阵只是一个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)

这段代码片段来自https://gist.github.com/nickynicolson/202fe765c99af49acb20ea9f77b6255e

输出:

   a  b  c
a  0  1  2
b  3  4  5
c  6  7  8

0
你的数据看起来有13个不同的类别,所以你的混淆矩阵有13行和13列。而且,你的类别没有任何标签,只是从我看到的整数。
如果不是这种情况,而你的训练数据有实际的标签,你可以将一个唯一标签列表传递给混淆矩阵。
conf_mat = confusion_matrix(class_label, class_label_predicted, df['task'].unique())

我的数据已经被标记。我有一个名为“task”列,每一行都有一个像t1、t2、t3等的值。我会尝试你的建议。 - fall2
哦,我得到了这个“numpy.ndarray”对象没有“unique”属性。 - fall2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接