关于监督学习、模型评估和预处理的一些问题

数据挖掘 分类 阶级失衡 预处理 监督学习 多标签分类
2022-03-02 11:30:35

我一直在尝试在我拥有的数据集上使用一些监督学习的基本技术,并且我对整个过程有几个问题(即数据预处理、模型评估等)。

在我开始提出问题之前,让我先让您了解一下我的数据集的样子。数据集来自开放的 ML 存储库,它由 22 种不同类型的文章(目标或类)和 1079 个不同的词(特征)组成。目的是根据这 1079 个单词对这些文章即将发布的简介进行分类。下面你可以看到我的数据集的前 5 行。

数据集的前 5 行

正如您在前 22 列中的上述片段中看到的那样,我有我的目标(即文章类型),其余列属于我的单词预测器。我的特征值是二进制的,即如果单词出现在简介中,则为“1”,否则为“0”。首先,我做了一些预处理,将目标与特征分开,将与目标对应的布尔值更改为 0 和 1,并为我的文章添加标签(即 0:«娱乐»,1:«采访“ ETC)。在下面的代码片段中,您可以看到我的样本根据每种不同类型的文章的分布情况。在此处输入图像描述

从上图中可以看出,我的数据集是不平衡的。我的目标是尝试以下分类算法并最终选择最好的一个:1)GaussianNB(GNB),2)KNearestNeighbors(KNN),3)LogisticRegression(LR),4)多层感知器(MLP)和5)支持向量机 (SVM)。在我开始更详细地预处理我的数据集之前,我将我的数据集拆分为 70% 的训练和 30% 的测试,并对这些算法进行了开箱即用测试,您可以在下表中看到我的结果

分类器 f1score(火车) 会计(火车) f1score(测试) ACC(测试) 时间 - f1score(train)
高斯NB 23 % 41 % 24 % 40 % 0.54(秒)
假的 1% 16 % 2% 19 % 0.01(秒)
1NN 4 % 18 % 8 % 24 % 0.22(秒)
物流 34 % 56 % 40 % 62 % 1.04(秒)
MLP 33 % 54 % 39 % 59 % 10.5(秒)
支持向量机 19 % 46 % 32 % 57 % 3.7(秒)

前两列是根据准确性和 f1(average = macro) 指标在我的训练集上使用 2 折交叉验证的分类器的结果,最后两列是根据测试集上的分类器的结果上述指标。从上表中您可以观察到其中一些分类器的性能较低。在我的下一个任务中,我将尝试使用 StandarScaler、VarianceThreshold、PCA 或 SelectBestK、RandomOverSampling 等技术更详细地预处理我的数据,并使用 GridSearch 优化我的分类器的参数。目前我可以提出我的第一个问题。

Q1上述技术(除了我完全理解的 GridSearch)是否肯定会提高分类器的性能?我的意思是有什么理由证明这些技术通常效果更好,或者它只是一个试验和观察程序?

在下一个代码中,我创建了一个管道,该管道执行以下操作,过采样,在训练模型之前依次删除具有低方差的特征(在这种情况下,我只使用 GaussianNB。请注意,我首先将数据集拆分为训练并测试然后使用过采样。

# Case 1 splitting first and then oversampling on training set
from imblearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from imblearn.over_sampling import RandomOverSampler
from sklearn.feature_selection import VarianceThreshold

selector = VarianceThreshold()
scaler = StandardScaler()
over = RandomOverSampler()
clf = GaussianNB()

pipe = Pipeline(steps = [('over', over),('selector', selector), ('scaler', scaler),\
       ('GNB', clf)])

train_new, test_new, train_new_labels,\
       test_labels_new = train_test_split(features, labels, test_size = 0.3) 

pipe.fit(train_new, train_new_labels)
pipe.score(test_new, test_labels_new)

以下管道的测试集的准确率为 38%,比没有此预处理程序的 GaussianNB 的分数低 2%,所以我的第二个问题如下。

Q2为什么这些修改会降低分类器的性能?我的数据集的值或其结构是否有任何迹象可以预测此结果?

现在,如果我更改拆分顺序和过采样,我会得到完全不同的结果,例如,如果我运行以下代码块。

# Case 2 oversampling before splitting

clf = GaussianNB()
features2, labels2 = over.fit_resample(features, labels) # First do the oversampling
train_new, test_new, train_new_labels, test_labels_new \
    = train_test_split(features2, labels2, test_size = 0.3) # Then do the splitting

train_new = selector.fit_transform(train_new)
test_new = selector.transform(test_new)                # This block of code does all
train_new = scaler.fit_transform(train_new)            # all the preprocessing.
test_new = scaler.transform(test_new)
train_new = selector2.fit_transform(train_new, train_new_labels)
test_new = selector2.transform(test_new)

clf.fit(train_new, train_new_labels)        # Fit on train
clf.score(test_new, test_labels_new)        # Evaluate on test

我在测试集上获得了 74% 的准确率,比以前好得多。所以我的问题是:

Q3为什么用过采样改变分割的顺序会改变结果呢?一般来说,我必须先进行拆分,然后只对我的训练集进行预处理?例如,我知道如果首先进行一些预处理,如缩放、PCA,然后拆分我的集合,那么我的结果将会有偏差,因为我也对测试集进行了预处理,但我不明白为什么过采样也会发生这种情况(如果就是这种情况)。

为了让您对下面的上述结果有另一种看法,我可以在第二种情况下向您展示 GaussianNB 在 10 倍交叉验证中的学习曲线,在这种情况下,我首先进行过采样,然后进行拆分。

在此处输入图像描述

从上面的代码片段可以看出,验证分数和训练分数收敛在同一个数字上,这很好地表明该模型可以实现良好的泛化性能。

Q4上述两种情况中哪一种更可靠,可以在未来未见的样本上给我带来好的结果?此外,您会建议对上述数据集进行什么样的预处理?例如,在这两次运行中,我从数据集中删除了属于 2 个或更多类的所有样本,这种修改让我恢复了初始数据集的 84%。如果我创建了这些样本的副本以尽可能多地防止数据集的不平衡,会更好吗?

PS:对不起,我的帖子很长,我不希望得到以上所有问题的答案,如果您对以上任何问题有任何有见地的答案,我将很高兴分享您的意见!提前致谢!

1个回答

第一季度

Q1 上述技术(除了我完全理解的 GridSearch)是否肯定会提高分类器的性能?我的意思是有什么理由证明这些技术通常效果更好,或者它只是一个试验和观察程序?

Q1 非常广泛,因为它涉及许多不同的技术,每种技术在某些情况下都有其用途,但一般情况下并非如此。总体而言,它不太可能总是对性能产生积极影响,尤其是在使用一组非常不同的学习算法时。但是如果使用得当,它不是一个试错过程,而是使用适当的技术来了解数据和算法的特征(以及它们可能存在的问题)。

第二季度

Q2 为什么这些修改会降低分类器的性能?我的数据集的值或其结构是否有任何迹象可以预测此结果?

可能大部分差异可以通过过采样来解释。我们在 DSSE 上看到很多关于重采样的问题,大概是因为这是一种非常简单的技术,有时会对性能产生很大影响……尤其是在使用错误的方式时!

了解重采样很有用,可能在少数情况下它是有意义的,但恕我直言,它通常只是避免正确研究特定数据和问题的懒惰选择,而且它也是混淆和错误的一大来源(见下问题)。一般来说,重采样根本不会提高性能,例如参见这个答案

第三季度

Q3 为什么用过采样改变分割的顺序会改变结果呢?一般来说,我必须先进行拆分,然后只对我的训练集进行预处理?

最重要的一点是要了解什么是监督学习中合适的评估方法:

  • 一个机器学习模型被训练来解决一个特定的“目标问题”,这个问题必须从一开始就明确定义。特别是类的分布是问题本身定义的重要组成部分。例如,在 N 个相等的类之间和 N 个不平衡的类之间进行分类不是同一个问题,针对一个问题训练的分类器不太可能对另一个问题很好地工作。
  • 从逻辑上讲,评估阶段必须始终代表定义的目标问题,当然包括类别分布。如果测试集不遵循目标问题的“真实分布”,则结果性能不可靠,因为我们根本不知道模型在真实分布上的表现如何。

在第三季度,模型根据过采样数据进行评估。除非您真的打算在此分布上使用模型(不太可能,因为它不是源数据中的模型),否则这种性能对于原始分布的真正目标问题没有任何意义。性能高得多的原因是平衡版本的问题要容易得多,所以就像解决一个简单的问题并假装它和原来的困难问题一样;)

第四季度

Q4 上述两种情况中哪一种更可靠,可以在未来未见的样本上给我带来好的结果?此外,您会建议对上述数据集进行什么样的预处理?例如,在这两次运行中,我从数据集中删除了属于 2 个或更多类的所有样本,这种修改让我恢复了初始数据集的 84%。如果我创建了这些样本的副本以尽可能多地防止数据集的不平衡,会更好吗?

根据上面的答案,未来未见过的样本可能遵循与源数据相同的分布,因此在另一个分布上计算的任何性能对此毫无意义。

出于同样的原因,删除或添加实例确实可以改变性能,但这也意味着改变目标问题。

另请参阅有关监督学习的这个问题,以防有帮助。