【问题标题】:Different Confusion Matrix with Cross-Validation具有交叉验证的不同混淆矩阵
【发布时间】:2022-01-12 11:19:27
【问题描述】:

很抱歉,如果这是一篇很长的帖子,但我有一些与混淆矩阵度量和交叉验证相关的问题,我真的需要帮助。

这张来自 Sklearn CV link 的图片显示我们的整个数据集应该被分成训练和测试。然后,训练集再次分成验证部分,我们在 k-1 折叠中训练我们的模型并在剩余的折叠中验证(重复这 k 次)。最后,我们从一开始就使用测试集测试我们的模型。

在我的问题中,我有一个包含42372 样本的不平衡二元分类问题的数据集。 3615属于1类,其余为0类。

由于我的数据集不平衡,我使用StratifiedShuffleSplit5 folds,得到了这个:

结果,使用MLPClassfier 我得到了以下混淆矩阵:

从该矩阵中可以看出,我的一半数据集用于测试 (19361+19+1782+28 = 21190)。

在这之后,我改变了CV策略,并尝试了StratifiedKfold

而且,作为混淆矩阵,我得到了这个:

从第二个混淆矩阵可以看出,我的整个数据集都用于测试 (38644+113+3329+286 = 42372)。

所以,这是我的问题:

1 - 我是否需要将整个数据拆分为训练/测试(例如,使用 train_test_split),然后提供 CV 迭代器(KFoldStratifiedKFoldStratifiedShuffleSplit 等) 与火车部分?或者我应该将我的整个数据输入到迭代器中,然后他们将完成将其拆分为训练/测试并将此训练再次拆分为训练和验证的工作?

2 - 关于我尝试的 CV 策略,为什么 StratifiedShuffleSplit 使用了一半的数据?为什么StratifiedKFold 使用所有数据?这些简历中的任何一个是错误的吗?两者都错还是都正确?我在这里缺少什么?

编辑:生成混淆矩阵的原始代码我发现here。我刚刚对其进行了一些修改以满足我的需要,如下所示:

import itertools
import time as time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
# from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import confusion_matrix

n_splits = 5  # Num of Folds
stratshufkfold = StratifiedShuffleSplit(n_splits=n_splits, random_state=0)
# stratshufkfold = KFold(n_splits=n_splits)

def generate_confusion_matrix(cnf_matrix, classes, normalize=False, title='Matriz de Confusão'):
    if normalize:
        cnf_matrix = cnf_matrix.astype('float') / cnf_matrix.sum(axis=1)[:, np.newaxis]
        print("Matriz de confusão normalizada")
    else:
        print('Matriz de confusão, sem normalização')

    plt.imshow(cnf_matrix, interpolation='nearest', cmap=plt.get_cmap('Blues'))
    plt.title(title)
    plt.colorbar()

    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes)
    plt.yticks(tick_marks, classes)

    fmt = '.2f' if normalize else 'd'
    thresh = cnf_matrix.max() / 2.

    for i, j in itertools.product(range(cnf_matrix.shape[0]), range(cnf_matrix.shape[1])):
        plt.text(j, i, format(cnf_matrix[i, j], fmt), horizontalalignment="center",
                 color="white" if cnf_matrix[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('Real')
    plt.xlabel('Predito')

    return cnf_matrix


def plot_confusion_matrix(predicted_labels_list, y_test_list):
    cnf_matrix = confusion_matrix(y_test_list, predicted_labels_list)
    np.set_printoptions(precision=2)

    # Plot non-normalized confusion matrix
    plt.figure()
    generate_confusion_matrix(cnf_matrix, classes=class_names, title='Matriz de confusão, sem normalização')
    plt.show()

    # Plot normalized confusion matrix
    plt.figure()
    generate_confusion_matrix(cnf_matrix, classes=class_names, normalize=True, title='Matriz de confusão normalizada')
    plt.show()

def evaluate_model_MLP(x, y):
    predicted_targets = np.array([])
    actual_targets = np.array([])
    global t_inicial_MLP
    global t_final_MLP
    t_inicial_MLP = time.time()
    for train_ix, test_ix in stratshufkfold.split(x, y):
        train_x, train_y, test_x, test_y = x[train_ix], y[train_ix], x[test_ix], y[test_ix]

        # Fit
        classifier = MLPClassifier(activation='relu', batch_size=56, solver='sgd').fit(train_x, train_y)

        
        predicted_labels = classifier.predict(test_x)

        predicted_targets = np.append(predicted_targets, predicted_labels)
        actual_targets = np.append(actual_targets, test_y)
    t_final_MLP = time.time()
    return predicted_targets, actual_targets


predicted_target_MLP, actual_target_MLP = evaluate_model_MLP(x, y)
plot_confusion_matrix(predicted_target_MLP, actual_target_MLP)
acuracia_MLP = accuracy_score(actual_target_MLP, predicted_target_MLP)

【问题讨论】:

  • 对于第一点,第一个选项是要走的路。对于您的第二个问题,imo,如果不查看您的代码,很难说出发生了什么。因此,我建议添加一段代码,以使您的示例可重现。
  • @amiola 我已经用代码编辑了帖子。我唯一无法分享的是数据库。但正如我所说,这是一个形状为(42372, 1036) 的二元分类问题,其中第一个3615 样本属于1 类,其余样本属于0 类。

标签: python scikit-learn cross-validation confusion-matrix


【解决方案1】:

如评论中所述,对于第一个问题,第一个选项是要走的路。即,通过train_test_split 拆分整个数据集,然后调用训练集上所选交叉验证器对象的方法.split()

对于第二点,问题隐藏在StratifiedKFoldStratifiedShuffleSplit的一些默认参数背后,以及参数n_splits的含义略有不同。

  • 对于StratifiedKFold 的关注点,参数n_splits 标识了您正在考虑根据documentation折叠数。因此,强加n_splits=5 意味着模型将在每个可能的组合上进行 4 倍训练(80% 的训练集)和 1 倍训练(20% 的训练集)。

  • 对于StratifiedShuffleSplit 的关注点,参数n_splits 指定了重新洗牌和拆分迭代的次数。另一方面,参数train_size(连同test_size)定义了折叠的大小(相对于训练集的大小)。特别是,根据docs,默认设置定义,如果没有指定,train_size=0.9(90% 的训练集)和test_size=0.1(10% 的训练集)。 因此,在 StratifiedShuffleSplit 构造函数中指定 test_size - 例如 - 应该可以解决您的问题:

    stratshufkfold = StratifiedShuffleSplit(n_splits=n_splits, random_state=0, test_size=0.2)

【讨论】:

    猜你喜欢
    • 2012-04-01
    • 2014-04-19
    • 2019-04-13
    • 2022-01-19
    • 2019-05-29
    • 2017-03-03
    • 2018-09-10
    • 2018-12-06
    • 2017-02-24
    相关资源
    最近更新 更多