在上一篇文章中,我们讨论了机器学习领域所面临的任务。无论解决的任务类别和方法如何,所有机器学习和数据科学领域的专家都使用了一组规则、方法和方法论。今天我将在这篇文章中着重讨论这些方法论。
,标签集 ,以及任务陈述,还有某种算法 ,我们知道如何训练(即调整该算法的参数,使得算法能够解决问题)。在接下来的文章中,我们将详细介绍这些算法的类型、如何训练这些算法以及如何评估它们的质量。而今天我们将讨论如何确保算法被正确地训练,并了解一些来自 sklearn 库的函数。
在机器学习中,对算法的处理分为两个阶段:
(1)算法训练
(2)训练后算法质量的验证
在某种程度上,可以将对算法的训练视为学生学习某一科目的过程。在这个比喻中,算法的训练类似于学生在课堂上解题,教师观察并及时给予反馈,学生有机会根据反馈调整解题策略,纠正错误。而模型测试阶段则类似于考试,学生需要在没有答案的情况下展示所学知识,同时没有教师的反馈,因此无法调整解题策略。
将数据集划分为训练集和测试集,这是为了避免在评估算法性能时误导自己。使用训练算法时的数据来评估其性能是不准确的,因为算法总是可以调整参数,使其在训练集上的表现良好,但在其他数据上可能不适用。
这与学校老师的做法相同:如果给学生布置了家庭作业,那么学生可能会翻阅课本末尾的答案,简单地记住它们,而不真正理解题目。因此,在考试中,必须给出与先前家庭作业不同的问题。在这种情况下,训练集就是家庭作业,其目的是训练学生,教会他们解决某一类型的问题。而测试集就像是考试,只有好学生才能很好地解答。因此,将数据集分为训练集和测试集就像是分配家庭作业和考试一样。
的函数:
为了举例说明,在二维平面上生成一个圆形数据集:
我们将每个点的标签设置为其坐标的总和。
能够按照相同的比例正确地分配到测试集和训练集中,与样本集的划分方式相对应。
函数。
正如各位所见,数据集中的点在训练集和测试集之间是以随机顺序分布的。这种随机性通常是必要的,以确保所得到的样本不具有代表性。为了解释这个概念,让我们看一个例子。
假设你想要根据照片区分玫瑰和郁金香。你请朋友从植物园收集了一小部分这些花的照片样本。你的朋友们对机器学习模型的训练细节一无所知,因此他们的操作如下:首先拍摄了75张郁金香样本的照片,然后才是25张玫瑰的照片。他们按照拍照顺序为这些照片编号,从1到100,并将它们以此形式交给了你。现在,如果你将这个样本分割成2:1的训练集和测试集,而没有对其进行随机化,你的算法可能会认为世界上所有的花都是郁金香,因为它所接收的所有数据都带有“郁金香”标签。
这只是最简单的例子,实际上数据中的隐藏关系可能更加复杂。因此,几乎总是需要对样本进行随机混洗。
但是,这也带来了一些问题。模型质量评估的结果取决于样本划分为训练集和测试集的方式。在最好的情况下,这种依赖关系非常微弱,具体对象进入训练集或测试集并不重要。但不幸的是,通常这种依赖关系是明显的。如果有人尝试在自己的计算机上重现您的结果,由于样本的随机性,其结果可能会与您的结果不同。
此外,通常在机器学习算法中也存在各种随机结构。我们将在今后学习诸如随机森林、神经网络、决策树等算法。所有这些算法在处理数据时都会以某种程度使用不同的随机元素。所有这些结构的综合效应可能会积累起来,使得无法重现你的结果!
但好在这个问题可以相对简单地解决。伪随机数是通过计算机算法生成的数列,虽然看起来是随机的,但实际上是可预测的。这个算法的基础是一个称为随机种子的预先设定的数字,通常被称为 random_seed。这个随机种子是伪随机数生成算法的起点,确定了生成的随机数序列。换句话说,给定相同的随机种子,相同的伪随机数算法将生成相同的随机数序列。
尽管随机种子看起来像是随机选择的数字,但实际上在大多数情况下是通过一些预定义的方式选择的。因此,尽管 random_seed 在传统意义上被认为是随机的,但事实上是可以确定的。
一旦知道了随机种子,就可以准确地重现使用该种子生成的所有伪随机数。因此,在开始使用随机数之前,建议设置初始化随机种子,以确保结果的可重现性,并在可能的算法中设置 random_state 值,以确保结果的一致性。
让我们来确保相同的 random_state 会给我们相同的结果,而不同的 random_state 会给出不同的结果。
你看!它们完全重叠在一起了!这正是我们想要的!
在某些情况下,对样本进行混洗可能会有害。有时数据本身的结构暗示着相邻元素之间的关联。例如,在许多涉及时间序列的问题中,需要保留原始数据的顺序。
在这种情况下,我们可以将 函数的 shuffle 参数设置为 False,即不混洗。
当我们处理分类问题时,通常会有一些样本属于某个类别,而另一些样本属于另一个类别。在某些情况下,某个类别的样本数量可能远远少于另一个类别。在将数据集划分为训练集和测试集时,我们希望训练集和测试集中的类别分布尽可能地保持一致。如果我们随机地将数据集划分为训练集和测试集,那么训练集和测试集中各个类别的样本数量可能会有很大差异,即类别比例不一致。这会导致模型在训练集上过度拟合于某个类别,而在测试集上性能不佳,因为测试集中某个类别的样本数量太少。
输出:5
我们再来检查一种情况,当以 4:1 的比例划分数据集时,训练集和测试集中标签的比例会发生什么变化。
输出:5
所有属于类别 1 的样本都被放入了训练集。这意味着现在训练集中类别的比例为:类别1占比 6.25%,类别2占比 93.75%,而测试集中,类别1占比 0%,而类别2占比 100%。这是一个显著的差异!
分层抽样是一种保持训练集和测试集中类别分布相同的技术。这意味着在划分数据集时,每个类别的样本数量在训练集和测试集中的比例应该与原始数据集中的比例相同。在 sklearn 中,可以通过在调用 函数时传递 stratify 参数来激活分层抽样方法。这个参数需要接收原始目标变量的标签向量作为参数,以确保在划分数据集时保持类别分布的一致性。通过在调用 函数时传递 stratify=Y_full 参数,就可以使用分层抽样方法。这样,训练集和测试集中每个类别的样本数量比例会与原始数据集中的比例相同。
输出:4
使用分层抽样方法时,我们可以确信训练集和测试集中各个类别的样本比例会与原始数据集中的类别比例保持一致。
备注一个小问题~
有时候在实践中,数据集的划分不是两部分,而是三部分。在这种情况下,第三部分称为验证集。这样做有三个原因:
(1)跟踪模型训练质量:有时候,我们训练的模型可能需要很长时间才能完成。在这种情况下,我们想要了解模型在训练过程中的表现如何。我们可以通过将一部分数据留出来,不参与模型的训练,而是用于在训练过程中监控模型的性能。这个留出来的数据集就是验证集。
(2)调整模型参数:有时候,我们使用的模型有一些参数是我们需要手动设置的,这些参数称为超参数。为了找到最佳的超参数组合,我们需要尝试不同的参数值,并选择表现最好的那个。在这个过程中,我们使用验证集来评估不同参数设置下模型的表现。
(3)最终评估模型:一旦我们确定了最佳的超参数设置,我们就可以使用整个训练数据来重新训练模型,并且使用之前未使用过的数据来评估模型的最终性能。这个未使用过的数据集就是测试集。
一般情况下,将数据集分成三个部分而不是两个更常见的情况是用于处理神经网络,而在我的专栏中,这个问题我们几乎不会涉及。
现在让我们想象一个不太可能但并非不可能的情况。一个差生意外地在不了解所学知识的情况下答出了一份很好的试卷。即使按照差生的标准,试卷也可能太简单了或者答案可能是猜出来的。我们的算法创建的测试集可能不具有很强的代表性。这使我们想到,最好使用多个测试集来更精确地评估算法。一种允许进行这种评估的方法是交叉验证。
交叉验证是一种用于评估机器学习模型性能的方法。它通过将现有的数据集分成多个部分来评估模型,每次使用其中一部分作为测试集,其余部分作为训练集。具体步骤如下:
(1)将数据集分成 n 个部分(通常称为折叠),这个数字由用户选择。
(2)在每次迭代中,将其中一个折叠作为测试集,剩余的 n-1 个折叠作为训练集。
(3)使用训练集来训练模型,并使用测试集来评估模型的性能。
(4)重复上述过程 n 次,每次使用不同的折叠作为测试集。
(5)最终,将所有的测试结果进行汇总,得到对所选模型性能的综合评估。
通过这种方法,每个数据点都会被用于测试一次,并且每个数据点也会被用于训练多次。这样可以确保模型的评估更加准确。此外,交叉验证也能够更加充分地利用现有的数据,因为每个数据点都有机会被用于训练和测试。
sklearn 库包含了各种不同的机器学习算法。这些算法分布在不同的模块中,其中我们主要关注以下模块:
(1)sklearn.linear_model: 提供了用于线性模型的工具,如线性回归、逻辑回归等。
(2)sklearn.tree: 提供了用于决策树相关算法的工具,如决策树分类器和回归器。
(3)sklearn.svm: 提供了用于支持向量机(Support Vector Machine,SVM)相关算法的工具,包括分类、回归和异常检测。
(4)sklearn.ensemble: 提供了用于集成学习的工具,包括随机森林、梯度提升等方法。
(5)sklearn.cluster: 提供了用于聚类分析的工具,如K均值聚类、层次聚类等。
(6)sklearn.neighbors: 提供了用于近邻算法的工具,包括最近邻分类、回归和密度估计。
函数来训练有监督学习算法和 函数来训练无监督学习算法。 函数是是 sklearn 库中机器学习算法类的方法,通过调用该方法并传递适当的数据,可以训练模型并使其适应给定的数据。
我来举个例子。在这种情况下,具体使用哪种算法并不重要。我们只想演示通用的算法工作流程。
首先我们会生成一个数据集。
函数来对未标记的数据进行预测。
在调用 函数时,我们将未标记的数据(特征矩阵) 作为参数传递给该函数。模型会使用学习到的参数和特征矩阵 来对每个样本进行预测,从而得到预测结果。
预测结果是模型对每个样本的预测值,这些预测值可能是连续的(如回归问题)或离散的(如分类问题)。我们可以使用这些预测值来进行进一步的分析或决策。
函数来简单地衡量模型的质量。该函数对数据集 进行模型预测,并将结果与真实标签 进行比较,使用以下两种函数之一:
(1)对于分类任务,使用 accuracy (正确预测的样本比例)
(确定系数),我们将在未来的课程中详细讨论这个指标
输出:0.9999782907844347
不同的机器学习算法可能需要不同的数据预处理方法,以便更好地应用于实际问题。这些预处理方法包括但不限于:
(1)特征缩放:将特征缩放到统一的尺度,以确保它们具有相似的范围。
(2)解码分类特征:将分类特征转换为数值特征,以便算法能够理解。
(3)标准化:对特征进行标准化处理,使其均值为0,方差为1。
(4)转换文本特征:将文本特征转换为数值特征,以便算法能够处理。
函数被替换为用于处理数据的 函数。
举一个最流行的预处理器的例子是 StandardScaler,它用于对数据进行标准化处理,即将特征缩放为均值为 0,方差为 1 的分布。
Standard Scaling - 标准缩放
标准缩放是统计学中一种常用的标准化过程:
代表平均值,通常用样本均值(数据集中 的平均值)替换,而 则表示标准差,通常也是通过数据集计算得出。
和 来实现这一点。
现在,我们可以很简单地编写一个缩放函数:
我们生成一个人工数据集并验证所有坐标是否确实被缩放。
当我们想要展示数据的分布情况时,可以使用 violinplot 这种可视化方法。在 violinplot 中,频率特征沿着水平轴进行展示,而垂直轴用于标记测量这些特征的值。
例如,让我们看看标准正态分布的图表是什么样子。
在这种情况下,Violinplot 将会有些不同:
А均匀分布,例如,会看起来像这样:
现在,我们可以看到,所有的特征在尺度上都有显著差异。我们将应用 函数:
当我们使用标准化方法对特征进行处理时,我们可以确保所有特征都具有相同的尺度,这样它们就可以直接进行比较和分析,而不会因为尺度不同而产生偏差。值得注意的是,虽然特征的数值范围发生了改变,但它们的平均值保持不变。
、 和 方法来进行标准化操作。
和 方法的作用与 和 方法类似,但是用于在我们只需要转换数据而不是进行预测时使用。在 sklearn 库中,所有的数据转换器都实现了这些方法。
在 sklearn 库中,可以通过 sklearn.datasets 模块的函数访问一些经典的数据集。例如,通过这个模块可以加载已经熟悉的经典鸢尾花数据集。
就是在这个模块中实现的。在这个模块中,还可以访问到用于执行交叉验证的工具。
函数,需要从 sklearn.model_selection 模块中导入它。
将返回一个数字数组:。
指的是当第 个“片段”数据被选择为测试集时,算法的性能评估。在这里,性能可以指不同的度量标准,这是可调整的参数,但基本上 意味着算法的准确率。
函数,我们将数据集分为了 个部分,并对每个部分执行了上述描述的过程,得到了 5 个评分(默认为准确率评分)。这些评分保存在 数组中。
函数:
、 方法的分类器都可以作为该参数。这些方法分别用于训练、预测和获取对象属于不同类别的概率。这样做非常方便,因为它允许我们不仅可以使用来自 sklearn 库的类对象作为 clf 参数,还可以使用其他库(甚至自定义的类)中的类对象。
(3)训练集中的标签
- 我们将数据集分成的“片段”数量
这组数字告诉我们很多信息:
通过平均值,我们可以确定我们的算法在平均情况下表现如何。在交叉验证中获得的一组度量标准的平均值通常被视为构建的算法的有效质量评估。
但是,这里有一些复杂性。假设我们得到以下一组数字:
这里的平均值将是 0.61,显然,这是由于第三个位置的异常好的结果。这个结果可能是由于某个子样本的偶然性或偏差导致的。我们不能将其视为绝对正确的。同样,平均值可能会误导我们,尤其是当数字数组的分散性很大时。例如,如果我们得到了以下交叉验证的结果:
显然,不能相信这里的平均值。我们应该寻找错误。通过在获得的数字数组中评估标准偏差,可以跟踪这些情况:标准偏差越小,使用平均值评估质量的可靠性就越高。
在 sklearn 库中,有一个方便的工具可以优化上述代码的所有内容。事实上,标准的机器学习任务具有相当可预测的解决方式:对数据应用一系列转换,训练某种分类器,计算质量指标。为了简化这个过程,开发了 Pipeline 类。
哎,又到了凌晨1:29了,今天先说这么多,后面的文章,一周一更哈!
各位,下周再见哈~
碎觉碎觉!