具有交叉验证的不同混淆矩阵

Different Confusion Matrix with Cross-Validation

很抱歉,如果这很长 post,但我有一些与混淆矩阵指标和交叉验证相关的问题,我真的需要帮助。

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

在我的问题中,我有一个不平衡二进制 classification 问题的数据集,样本为 423723615属于class1,其余为class0.

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

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

正如您从该矩阵中看到的那样,我的数据集有一半用于测试 (19361+19+1782+28 = 21190)。

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

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

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

所以,这是我的问题:

1 - 我是否需要将整个数据拆分为 train/test(例如,使用 train_test_split),然后提供 CV 迭代器(KFoldStratifiedKFoldStratifiedShuffleSplit,等等)只有火车部分?或者我应该将我的全部数据输入迭代器,它们将完成将其拆分为 train/test 并将这列火车再次拆分为火车和验证的工作?

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)

如评论中所述,对于第一个问题,第一个选项是要走的路。即,通过 train_test_split 拆分整个数据集,然后在 训练集 .

上调用所选交叉验证器对象的方法 .split()

对于第二点,问题隐藏在StratifiedKFoldStratifiedShuffleSplit的一些默认参数背后,以及参数n_splits.

的略微不同的含义上
  • 关于 StratifiedKFold,参数 n_splits 确定 折叠数 您根据 documentation.因此,强加 n_splits=5 意味着模型将在 4 倍(训练集的 80%)上训练,并在每个可能的组合上测试一次(训练集的 20%)。

  • 关于StratifiedShuffleSplit,参数n_splits指定了重新洗牌和分裂的迭代次数。另一方面,参数 train_size(连同 test_size)定义了折叠的大小(相对于训练集的大小)。特别是,根据 docs,默认设置定义为,如果指定其中的 none,则 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)