机器学习和神经网络 - 页 68

 

4.5 NumPy 高级索引——内存视图和复制(L04:Python 中的科学计算)



4.5 NumPy 高级索引——内存视图和复制(L04:Python 中的科学计算)

在这第五个视频中,我们将再次深入探讨索引主题。但是,与我们介绍基本索引的初始视频不同,我们现在将探索高级索引。本节将介绍内存视图和创建内存副本等概念,这些都是避免意外错误(例如错误地覆盖数组值)的重要实践。了解这一点至关重要,因为它可以帮助我们防止 NumPy 中的错误和意外行为。

现在,让我们开始吧。在上一节中,我们讨论了 NumPy 数组的一个方面,称为“视图”。视图是在我们使用常规索引或基本切片操作时创建的。这些视图充当隐式维度,使我们能够执行在线性代数的严格数学框架内不可行的操作。但是,使用视图可能会有风险,因为我们可能会在没有意识到的情况下意外修改原始数组。

为了说明这一点,让我们考虑一个简单的例子。假设我们有一个两行三列的二维数组。为方便起见,我会将第一行分配给一个名为“first_row”的单独变量。现在,这里是关键点:将第一行分配给一个变量会创建一个视图,而不是一个新对象。这意味着该变量仅指向原始数组在内存中的位置。因此,如果我们修改这个变量中的值,我们也会修改原始数组中的相应值。

为了演示这一点,让我们将“first_row”变量中的每个元素递增 99。执行此操作不仅会更改变量中的值,还会覆盖原始数组第一行中的值。此行为暗示我们正在使用视图而不是独立对象。不知道这一点可能很危险,因为在使用视图时很容易无意中覆盖原始数组中的值。

另一方面,视图对于提高内存效率非常有用,因为它们使我们能够避免不必要的数组复制。但是,在某些情况下,我们可能希望显式创建数组的副本。为此,我们可以使用“复制”功能,它会生成一个与原始数组具有相同值的新数组。在提供的示例中,我使用“复制”函数创建了数组第二行的副本。通过这样做,对“first_row”变量所做的任何修改都不会影响原始数组。

重要的是要注意,虽然切片和基于整数的索引创建内存视图,但还有另一种类型的索引称为“花式索引”,它会生成数组的副本。花式索引是指使用多个整数索引从数组中选择特定元素。这个特性被称为“花哨的”,因为它在常规的 Python 列表中不受支持。然而,NumPy 允许我们执行这种类型的索引,这可能非常强大。

例如,在常规 Python 列表中,我们不能同时检索第一个和第三个元素。然而,在 NumPy 中,我们可以使用花哨的索引来实现这一点。同样,我们可以使用花式索引从二维数组中选择特定的列。值得注意的是花哨的索引总是产生数组的副本,而不是视图。

视图和副本的区别与 NumPy 中的效率考虑有关。切片允许我们在内存中缓存某些值,优化性能。然而,用奇特的索引实现这种缓存机制并不简单,因为我们无法提取连续的内存块。相反,我们选择单个值,从而创建一个新数组。这种行为解释了为什么花式索引生成副本而不是视图。

花式索引的另一个有趣的方面是它使我们能够重新排列数组中列的顺序。通过使用花式索引指定所需的列索引,我们可以根据需要随机排列列。

NumPy 中的布尔掩码是一种基于特定条件过滤数组的有效且强大的方法。布尔掩码只是一个布尔值(True 或 False)的 NumPy 数组,其形状与原始数组相同。通过将布尔掩码应用于原始数组,我们可以选择满足给定条件的元素并丢弃其余元素。

要创建布尔掩码,我们首先定义一个条件,为数组中的每个元素返回一个布尔值。例如,假设我们有一个名为 arr 的数组:

import numpy as np
arr = np.array([1, 2, 3, 4, 5])
我们可以根据条件创建一个布尔掩码,比如只选择大于 3 的元素:
mask = arr > 3
生成的布尔掩码 mask 将为 [False, False, False, True, True]。掩码中的每个元素对应于原始数组中的相同位置,指示该元素的条件是真还是假。

要应用布尔掩码并检索满足条件的元素,我们可以简单地使用掩码作为数组的索引:

filtered_arr = arr[mask]
生成的 filtered_arr 将为 [4, 5],其中仅包含原始数组中大于 3 的元素。

可以使用 &(和)、| 等逻辑运算符组合布尔掩码(or), and ~ (not) 创造更复杂的条件。例如:

mask = (arr > 2) & (arr < 5)
filtered_arr = arr[mask]
此条件选择大于 2 且小于 5 的元素,导致 filtered_arr 为 [3, 4]。

布尔掩码在处理大型数据集或执行数据过滤和分析时特别有用。它们允许对数组进行高效和简洁的操作,而无需显式循环或条件检查。

除了过滤数组,布尔掩码也可以用于元素赋值。通过布尔掩码为选定元素分配新值,我们可以根据条件修改数组的特定部分。

总体而言,布尔掩码提供了一种灵活高效的方式来根据指定条件操作和过滤 NumPy 数组,使其成为数据处理和分析中的宝贵工具。

 

4.6 NumPy 随机数生成器(L04:Python 中的科学计算)



4.6 NumPy 随机数生成器(L04:Python 中的科学计算)

在本视频中,我们将简要概述 NumPy 中的随机数生成器。虽然我们不会涵盖在 NumPy 中生成随机数的所有不同方法,但我们的重点将放在理解随机数生成器及其实用程序上。

让我们从一个简单的例子开始。我们将从导入 NumPy 开始,这是我们将用于生成随机数的库。 NumPy 有一个随机模块,其中包含用于绘制随机数的各种函数。虽然我们要参考的文档有点过时,但它提供了一个有用的不同功能列表及其描述。

一个常用的函数是 random.rand,它从均匀分布中生成随机样本。通过指定所需数组的形状(例如,2x3),此函数将生成一个二维数组,其中填充了均匀分布的随机数。

NumPy 还提供其他函数,例如 random.random,它在半开区间 [0, 1) 中生成随机浮点数。您还可以使用 random.randn 函数从不同的分布中抽取随机样本,例如标准正态分布。

有时,我们可能希望确保我们的代码在每次执行时都产生相同的随机结果。这对于可重复性很有用,尤其是在共享代码或比较不同方法时。为此,我们可以在代码或笔记本的开头设置一个随机种子。种子是一个任意数,可确保每次生成相同的随机数序列。

通过设置随机种子,生成的随机数将在代码的多次运行期间保持不变。但是,需要注意的是,如果我们再抽取一个随机样本,结果会有所不同,因为它仍然是一个随机过程。

获得一致的结果在机器学习应用程序中特别有用,例如改组数据或测试实施。例如,在拆分数据集时,设置随机种子可确保每次拆分都相同。这允许对不同的方法进行准确的比较和评估。

为了更精细地管理随机性,我们可以在 NumPy 中使用随机状态对象。随机状态对象有自己的随机数生成器,可以对应用随机性的位置进行细粒度控制。通过创建多个随机状态对象,我们可以在代码中拥有不同的随机源。当我们希望代码的某些部分产生一致的结果而其他部分产生不同的随机数时,这尤其有用。

虽然旧的 random_state 类仍在广泛使用,但 NumPy 社区现在建议使用新的随机生成器。这个新的生成器采用不同的方法来生成随机数,但对于大多数简单的应用程序,两者之间的选择不会产生明显的差异。最重要的是为可重复性设置一个随机种子。

重要的是要记住,代码中的随机数生成器不是真正随机的,而是伪随机的。他们使用算法来生成模拟随机性的数字序列。在我们的上下文中,重点是一致性和可重复性,而不是用于随机数生成的特定算法。

总之,在 NumPy 中使用随机数生成器时,生成器本身的选择并不重要。重要的是设置随机种子以确保一致且可重现的结果。这在共享代码、提交作业或比较不同方法时变得特别有价值。

 

4.7 重塑 NumPy 数组(L04:Python 中的科学计算)



4.7 重塑 NumPy 数组(L04:Python 中的科学计算)

最后,我们接近 NumPy 系列的结论。只剩下三个视频了,我们已经谈到了一个重要的话题:重塑 NumPy 数组。当我们需要将数据转换为所需的形状时,例如将矩阵转换为向量或将矩阵转换为向量,重塑数组是至关重要的。我在介绍性讲座中简要提到了这个概念,在那里我讨论了 MNIST。为了说明这个过程,让我们考虑一个简化的例子。

假设我们有一个 28 x 28 维的数组,表示一个图像。通常,数组中的每个元素都对应一个像素值。但是,为了简单起见,我们假设每个元素只是一个数字。所以我们有一个 28 x 28 的数组来表示数字图像。然而,如果我们想将这个数组用作分类器的特征向量,我们需要将它重新整形为一个包含 784 个元素 (28 * 28) 的长向量。每个训练样例都是一张图像,每张图像有 784 个特征。

可以使用 NumPy 中的重塑函数来重塑数组。例如,我们可以将向量 1、2、3、4、5、6 重塑为 2×3 矩阵:

array([[1, 2, 3],
       [4, 5, 6]])
请务必注意,整形期间指定的维度必须与原始数组中的元素总数相匹配。如果尺寸不正确,则会发生错误。例如,尝试将 6 元素向量重塑为 3 x 3 矩阵会引发错误,因为没有足够的元素。

重塑数组时,会创建内存视图而不是新数组。这个内存视图允许我们在不复制数据的情况下操作重塑的数组。为了验证这一点,我们可以使用 np.may_share_memory 函数,尽管它可能并不总是提供 100% 准确的结果。

在重塑中使用 -1 作为维度是 NumPy 中的一项便利功能。它充当占位符,允许该方法根据元素总数确定适当的维度。例如,如果我们有一个包含六个元素的向量并使用 -1、2 对其进行整形,则 -1 将被替换为 3,因为只有一种方法可以将三行两列排列以获得六个元素。此占位符概念适用于任意数量的维度。

此外,我们可以使用 reshape 函数来展平数组。通过指定单个值作为维度(例如,reshape(6)),我们可以将数组转换为一维向量。实际上,使用 -1 更方便,因为它无需记住大小。例如,对于六元素数组,reshape(-1) 实现与 reshape(6) 相同的结果。

在 NumPy 中有多种方法可以展平数组。带有 -1 的 reshape 函数创建一个内存视图,而 flatten 函数也压平一个数组但创建一个副本。另一个函数 ravel 也用于展平数组。确定这些功能之间的差异将是一个很好的自我评估测验。

最后,我们可以在 NumPy 中连接数组,沿着指定的轴组合它们。沿第一个轴连接数组时,类似于在 Python 列表中附加元素。例如,如果我们有两个带有一个轴的数组,那么将它们沿该轴连接起来将一个堆叠在另一个下方。

重塑 NumPy 数组对于将数据操作成所需的形状至关重要。了解各种方法、占位符和连接技术使我们能够有效地使用数组并优化我们的代码。在下一个视频中,我将讨论 NumPy 比较运算符和掩码,它们是与重塑结合使用时的强大工具。

 

4.8 NumPy 比较运算符和掩码(L04:Python 中的科学计算)



4.8 NumPy 比较运算符和掩码(L04:Python 中的科学计算)

在 NumPy 中,比较运算符和选择掩码提供了很大的灵活性,并且使用起来非常愉快。在之前的视频中,我们介绍了掩码和比较运算符,但现在让我们探索一些您在使用它们时可以使用的额外技巧。

让我们从一个简单的例子开始。为简单起见,假设我们有一个 NumPy 数组 [1, 2, 3, 4]。我们可以定义一个掩码来从数组中选择某些值。此掩码将是一个布尔数组,这意味着它将包含 True 或 False 值。我们可以通过指定条件来创建掩码,例如选择大于 2 的值。生成的掩码数组将与原始数组具有相同的形状,True 值表示条件为真的位置,False 值表示条件为假的位置。

在 Python 中,布尔值和整数之间有一个很方便的关系:True 相当于 1,False 相当于 0。这种关系允许我们执行有趣的操作。例如,我们可以使用 if 语句通过简单地编写 if condition: 来检查条件是否为真。我们还可以使用 not 运算符通过编写 if not condition: 来检查条件是否为假。与显式比较条件与 True 或 False 相比,这些方法提供了更具可读性的代码。

另一个有用的功能是能够计算数组中符合特定条件的元素的数量。通过将求和运算符应用于掩码,我们可以计算掩码中真值的数量。例如,如果我们有一个选择大于 2 的值的掩码,我们可以通过调用 sum(mask) 来计算此类值的数量。类似地,我们可以通过从数组中的元素总数中减去总和来计算 False 值的数量。

要计算数组中负值的数量,我们可以使用 NumPy 的反转函数,它翻转掩码中的布尔值。通过将 invert 应用于掩码然后调用 sum,我们可以计算 False 值(现在表示负值)的数量。

将数组二进制化,即,将其转换为二进制表示,是另一种常见操作。我们可以通过为条件为真的位置分配一个特定值,为条件为假的位置分配另一个值来实现这一点。但是,键入整个操作可能很乏味。幸运的是,NumPy 提供了 where 函数,简化了这个过程。 where函数接受一个条件,对于条件为真的位置,它赋值第一个值,对于条件为假的位置,它赋值第二个值。使用where,我们可以轻松地用一行代码对数组进行二值化。

除了比较运算符之外,NumPy 还提供逻辑运算符,例如 and、or、xor 和 not。这些运算符可以与掩码结合使用以创建更复杂的条件。例如,我们可以使用 or 运算符选择大于 3 或小于 2 的值。通过使用逻辑运算符组合多个条件,我们可以创建适合我们需要的复杂选择掩码。

NumPy 中的这些布尔掩码、逻辑运算符和比较运算符在处理数据集和实施决策树规则时非常有用。我们将在接下来的视频中进一步探讨这些概念。在下一个视频中,我们将深入探讨 NumPy 中的基本线性代数概念。敬请关注!

 

4.9 NumPy 线性代数基础(L04:Python 中的科学计算)



4.9 NumPy 线性代数基础(L04:Python 中的科学计算)

在本视频中,我想深入探讨线性代数的一些基本概念,特别是在 NumPy 的背景下。虽然我们不会在本课程中广泛使用线性代数,但掌握基本运算(如向量点积和矩阵乘法)至关重要。正如我之前提到的,使用线性代数符号使我们能够编写更高效、更简洁的代码。

让我们首先将一维数组视为行向量。或者,我们可以将其定义为由单行和多个元素组成的向量。另一方面,可以通过将行向量整形为具有一列和多个元素来创建列向量。本质上,它表示列向量表示。值得注意的是,在这种情况下不需要使用方括号。

我们可以通过使用 NumPy 的 newaxis 函数添加一个新轴来实现相同的结果,而不是显式地重塑向量。通过添加两个新轴,我们甚至可以创建一个 3D 张量。另一种方法是使用 None 关键字,其作用与 newaxis 相同。 reshaping、newaxis、None这三种方法,都是为了达到在需要的时候增加一个额外的轴的目的。

继续前进,我们遇到了矩阵乘法的基本线性代数符号。在线性代数中,矩阵乘法相当于计算多个点积。例如,如果我们有向量 [1, 2, 3] 和 [1, 2, 3],它们的点积结果为 14。类似地,[4, 5, 6] 和 [1, 2, 3] 产生 32。在 NumPy 中,我们可以使用 matmul 函数执行矩阵乘法。或者,可以使用 @ 运算符以方便使用。但是,需要注意的是,在线性代数中,我们不能直接将矩阵和向量相乘。然而,我们可以将列向量视为矩阵,具体而言是 3x1 矩阵。这种方法使我们能够将矩阵与向量相乘,这在严格的线性代数中是不可能的。因此,与传统的线性代数相比,NumPy 提供了更大的灵活性。

此外,NumPy 提供了用于矩阵乘法的 dot 函数,由于其在大多数机器上的高效实现而被广泛推荐。这个函数可以让我们写代码更方便,尤其是在处理行向量的时候。它用作 NumPy 中矩阵乘法的快捷方式或运算符重载。值得注意的是,点函数可以处理矩阵和向量的各种组合,根据输入形状执行点积或矩阵乘法。

关于性能,matmul 和 dot 函数具有相似的速度。它们之间的选择可能取决于特定的机器。尽管如此,点功能在实践中通常受到青睐。此外,转置运算的作用类似于线性代数中的转置运算,有效地翻转矩阵。为了简洁起见,我们可以使用 T 属性,而不是显式使用转置函数。

虽然 NumPy 包含二维数组的矩阵类型,但它在 NumPy 社区中并不常用。在大多数情况下,常规的多维数组都能达到目的。矩阵类型仅限于二维并引入了不必要的复杂性。除非特别需要,否则建议避免使用它。

最后,我们简要介绍一下 SciPy,这是一个令人印象深刻的库,它包含 NumPy 之外的大量附加功能。该库包含许多用于科学计算的专用算法,例如线性代数运算、傅里叶变换、插值技术、优化算法、统计函数等。虽然它基于 NumPy,但 SciPy 作为扩展,为各种科学计算提供专门的工具。在本课程中,我们将根据需要探索 SciPy 中的特定算法。你不需要记住所有的细节;相关算法我会边遇到边介绍和解释。

至此,我们结束了关于使用 Python 进行科学计算的 NumPy 和 SciPy 的讨论。在下一个视频中,我们将通过探索强大的绘图库 matplotlib 继续我们的科学计算之旅。

 

4.10 Matplotlib(L04:Python 中的科学计算)



4.10 Matplotlib(L04:Python 中的科学计算)

终于,我们到了第四讲的结尾,这已经很长了。但是,我希望所讨论的有关 NumPy 的概念对您有价值。将来,我们将在家庭作业中广泛使用 NumPy 来实现机器学习算法。因此,此时精通和熟悉NumPy对你来说至关重要。

继续第四讲的最后一个主题,我们将探索 matplotlib,这是一个流行的 Python 绘图库。尽管现在有几个可用的绘图库,但 matplotlib 仍然是使用最广泛的一个。就个人而言,它也是我最喜欢的绘图库,其名称的灵感来自 Metalab。 matplotlib 的语法与 MATLAB 非常相似,有些人喜欢,有些人则不喜欢。例如,我在研究生期间不喜欢使用 MATLAB,但我发现 matplotlib 是一个很棒的工具。

即使你不是 MATLAB 的粉丝,我相信 matplotlib 也相对容易使用。此外,它可以与 NumPy 顺利集成,这是一个额外的优势。那么,让我们开始使用 matplotlib。我个人应该提一下,我不会记住所有在 matplotlib 中完成任务的特殊方法,因为它是一个低级库。这意味着它提供了高级定制选项,但并非所有选项都是直观的。因此,我经常发现自己在查找东西。当我需要做一些特定的事情时,我会访问展示各种示例的 matplotlib 画廊。例如,如果我想创建一个针状图,我只需在图库中搜索它,找到示例,然后根据我的数据进行调整。这种方法通常足以满足我的需要。但是,如果您更喜欢更详细的教程,也可以浏览 matplotlib.org 网站,该网站提供了有关 matplotlib 不同方面的解释性教程。

首先,在 Jupyter Lab 或 Jupyter Notebooks 中使用 matplotlib 时,您可以使用内联函数在笔记本本身中显示绘图。这意味着绘图将直接显示在笔记本中,无需单独的窗口。虽然有其他方法可以实现这一点,但我个人建议使用内联方法,因为它在不同计算机上更可靠。要激活内联模式,您可以使用以下神奇命令:%matplotlib inline。或者,您可以在绘图语句的末尾添加一个分号,这通常会获得相同的结果。但是,建议使用 plt.show() 来显示绘图,因为分号技巧在某些计算机上可能无法正常工作。

现在让我们深入研究如何使用 matplotlib 创建一些简单的绘图。例如,我们可以从绘制正弦曲线开始。为此,我们可以使用 np.linspace 函数生成 100 个值,范围从 0 到 10,然后根据 np.sin(正弦函数)绘制这些值。创建绘图的最简单方法是使用 plt.plot 函数,其中 plt 是 matplotlib.pyplot 的缩写。我们可以使用 plt.xlim 和 plt.ylim 函数调整绘图的轴范围,分别设置 x 轴和 y 轴的范围。此外,我们可以使用 plt.xlabel 和 plt.ylabel 函数将标签添加到 x 轴和 y 轴。最后,要显示绘图,我们可以使用 plt.show() 函数或在绘图语句末尾添加分号以抑制不需要的输出。

除了单个图,我们还可以在同一个图中创建多个图。例如,我们可以在单独的子图中同时绘制正弦曲线和余弦曲线。为此,我们可以使用 plt.subplots 函数创建两个图形,然后在每个子图中绘制相应的正弦和余弦曲线。 plt.subplots 函数返回一个图形对象和一个轴对象数组,我们可以使用它们分别自定义每个子图。

这是一个示例代码片段,演示了多个子图的创建:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace( 0 , 10 , 100 )
y1 = np.sin(x)
y2 = np.cos(x)

fig, axs = plt.subplots( 2 , 1 )  # Create a figure with 2 subplots arranged vertically

# Plot the sine curve in the first subplot
axs[ 0 ].plot(x, y1)
axs[ 0 ].set_title( 'Sine Curve' )  # Set a title for the subplot
axs[ 0 ].set_xlabel( 'X' )
axs[ 0 ].set_ylabel( 'Y' )

# Plot the cosine curve in the second subplot
axs[ 1 ].plot(x, y2)
axs[ 1 ].set_title( 'Cosine Curve' )
axs[ 1 ].set_xlabel( 'X' )
axs[ 1 ].set_ylabel( 'Y' )

plt.tight_layout()  # Adjust the spacing between subplots for better readability
plt.show()  # Display the figure
在此示例中,我们使用 plt.subplots 函数创建一个图,其中包含 2 个垂直排列的子图 (2, 1)。该函数返回一个图形对象 fig 和一个轴对象数组 axs ,其尺寸与指定的子图布局匹配。我们可以通过索引 axs 数组来访问每个子图。

在特定于子图的代码块中,我们使用 plot 函数绘制相应的曲线,然后分别使用 set_title、set_xlabel 和 set_ylabel 函数自定义每个子图的标题、x 轴标签和 y 轴标签。

调用 tight_layout 函数来调整子图之间的间距,确保更好的可读性。最后,我们使用 plt.show() 来显示包含子图的图形。

您可以尝试在 Jupyter Notebook 或 Jupyter Lab 环境中运行此代码,以查看结果图,其中正弦和余弦曲线显示在单独的子图中。

这只是创建子图的一个基本示例,matplotlib 中还有更多自定义选项可用,可以让您的图提供更多信息并在视觉上更具吸引力。您可以浏览 matplotlib 文档和图库以获取更多示例和详细说明。

 

5.1 从表格文本文件中读取数据集(L05:使用 Scikit-Learn 进行机器学习)



5.1 从表格文本文件中读取数据集(L05:使用 Scikit-Learn 进行机器学习)

大家好!我希望你们都度过了愉快的一周,并有机会学习所有 NumPy 材料。本周,我们将专注于使用 scikit-learn 进行数据处理和机器学习,因此对 NumPy 有一个很好的理解是必不可少的。我相信练习编码和应用我们在现实生活中的例子中学到的概念是非常有用的,这就是为什么我们将在本讲座中预先进行一些编码。当我们广泛使用这些工具时,这将使我们在课堂后面受益。说到这一点,除了我已经上传了第一个大型家庭作业外,本次讲座没有太多要补充的内容,它将测试您在之前讲座中介绍的概念,包括监督学习和使用 NumPy 的代码示例。这是获得 K 近邻算法实践经验并进一步探索 NumPy 和 scikit-learn 的绝佳机会。

现在,当您深入观看视频、完成作业并参加自我评估测验时,我想提醒您找点乐子,享受自己。秋天,我最喜欢的季节,在威斯康星州刚刚开始,我喜欢寒冷的天气和不断变化的树叶的美丽色彩。顺便说一句,我真的很兴奋,因为上周末我已经去了南瓜园,买了一些我迫不及待想为万圣节雕刻的南瓜。那么,让我们开始讲课吧,这样我就可以回到我的小南瓜上,为万圣节做准备了。

好的,我们现在已经完成了计算基础讲座的第三部分。在本讲座中,我们将涵盖几个主题,首先是从表格文本文件(例如 CSV 文件)读取数据集,这是传统机器学习任务最常见的文件格式。然后我们将讨论基本的数据处理技术,包括为机器学习算法和训练程序塑造数据。

之后,我们将使用 scikit-learn 深入研究机器学习。但在开始之前,我想简要回顾一下 Python 类和面向对象编程。在前面的练习中,我要求您为 Python 做好准备或更好地理解它的概念。掌握面向对象编程很重要,因为 scikit-learn 严重依赖它。因此,理解面向对象编程对于理解 scikit-learn 的工作原理是必要的。

接下来,我们将讨论使用 scikit-learn transformer API 准备训练数据。我们还将介绍定义 scikit-learn 管道,这有助于我们链接不同的操作,例如数据集准备、缩放、规范化、降维和分类器本身。通过使用管道,我们可以创建连接机器学习过程各个方面的高效训练工作流,让事情变得更加方便。这是 scikit-learn 的重要优势之一。

对于本次讲座,我决定再次使用幻灯片。尽管 Jupiter Lab 是一个很棒的工具,但我发现通过用钢笔或铅笔注释代码示例来更容易解释某些概念。因此,在这些幻灯片中,我截取了 Jupiter Lab 和 Jupiter Notebook 的屏幕截图,我将在讲座中对其进行注释。不过,我也已将整个代码笔记本上传到 GitHub,您可以在其中找到更多解释。将此文档视为可选课程或讲义供您参考。

让我们快速回顾一下我们在本课程中的进展。我们首先介绍了机器学习,涵盖了基础知识,并探索了 scikit-learn 的工作原理。然后,我们深入研究了 Python,学习了 NumPy 和科学计算。现在,我们正在进入使用scikit-learn进行数据处理和机器学习的阶段。在下一讲中,我们将回归决策树、集成方法和模型评估等核心机器学习概念。虽然这是计算基础课程的最后一部分,但这并不意味着课程就此结束。完成计算基础课程后,我们将继续学习机器学习中更高级的主题,包括深度学习和神经网络。

现在,让我们深入探讨本讲座的第一个主题:从表格文本文件中读取数据集。使用机器学习时,数据通常以表格格式存储,例如 CSV(逗号分隔值)文件。这些文件包含数据的行和列,每行代表一个样本或实例,每列代表一个特征或属性。

要用 Python 读取 CSV 文件,我们可以使用 Pandas 库。 Pandas 提供了强大的数据操作和分析工具,使其成为在 Python 中处理表格数据的热门选择。让我们看一个例子:

import pandas as pd

# Read the CSV file into a DataFrame
data = pd.read_csv( 'data.csv' )

# Display the first few rows of the DataFrame
print(data.head())

在本示例中,我们首先导入 pandas 库,并为方便起见将其别名为 pd。然后,我们使用read_csv()函数将CSV文件data.csv读入DataFrame,DataFrame是Pandas提供的二维表格数据结构。 DataFrame 存储在变量数据中。

读取数据后,我们可以使用 head() 函数显示 DataFrame 的前几行。这使我们能够快速检查数据并验证它是否被正确读取。

Pandas 提供了广泛的函数和方法来操作和分析数据。我们可以执行各种操作,例如过滤行、选择列、聚合数据等等。如果您是 Pandas 的新手,我鼓励您浏览其文档并自行尝试不同的操作。

现在我们知道如何读入数据,让我们进入下一个主题:基本数据处理技术。在为机器学习处理数据时,必须适当地预处理和准备数据。这包括处理缺失值、编码分类变量、缩放数字特征以及将数据拆分为训练和测试集等任务。

一个常见的预处理步骤是处理缺失值。缺失值在数据中通常表示为 NaN(非数字)或 NULL 值。这些缺失值可能会在训练机器学习模型时引起问题,因此我们需要适当地处理它们。 Pandas 提供了几个函数来处理缺失值,例如 isna() 检查缺失值,fillna() 用指定值填充缺失值,以及 dropna() 删除具有缺失值的行或列。

编码分类变量是另一个重要步骤。机器学习模型通常使用数值数据,因此我们需要将分类变量转换为数值表示。一种常见的编码技术是单热编码,我们为每个类别创建二进制列,并分别用 1 或 0 表示类别的存在或不存在。

import pandas as pd

# Create a DataFrame with categorical variables
data = pd.DataFrame({ 'color' : [ 'red' , 'blue' , 'green' , 'red' , 'green' ]})

# Perform one-hot encoding
encoded_data = pd.get_dummies(data)

# Display the encoded data
print(encoded_data)
在此示例中,我们创建了一个 DataFrame,其列“color”包含分类变量。然后我们使用 Pandas 的 get_dummies() 函数来执行单热编码。生成的编码数据包含原始“颜色”列中每个唯一类别的二进制列。

缩放数值特征是另一个常见的预处理步骤。许多机器学习算法对特征的规模很敏感。如果特征具有不同的尺度,它会影响模型的性能。为了解决这个问题,我们可以将特征缩放到一个标准范围,例如 0 到 1 或 -1 到 1。Pandas 在 sklearn.preprocessing 模块中提供了 MinMaxScaler 和 StandardScaler 类来执行特征缩放。

import pandas as pd
from sklearn.preprocessing import MinMaxScaler

# Create a DataFrame with numerical features
data = pd.DataFrame({ 'age' : [ 25 , 30 , 35 , 40 ], 'income' : [ 50000 , 60000 , 70000 , 80000 ]})

# Perform feature scaling using MinMaxScaler
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(data)

# Convert the scaled data back to a DataFrame
scaled_df = pd.DataFrame(scaled_data, columns=data.columns)

# Display the scaled data
print(scaled_df)
在此示例中,我们创建了一个具有两个数字特征的 DataFrame:“年龄”和“收入”。然后我们使用 sklearn.preprocessing 模块中的 MinMaxScaler 类来执行特征缩放。 fit_transform() 方法对数据进行缩放,缩放后的数据作为 NumPy 数组存储在 scaled_data 变量中。最后,我们将缩放后的数据转换回 DataFrame 并显示它。

最后,将数据分成训练集和测试集对于评估机器学习模型的性能至关重要。我们通常将数据分成两组:用于训练模型的训练集和用于评估其性能的测试集。 Pandas 在 sklearn.model_selection 模块中提供了 train_test_split() 函数,用于将数据拆分为训练集和测试集。

import pandas as pd
from sklearn.model_selection import train_test_split

# Read the CSV file into a DataFrame
data = pd.read_csv( 'data.csv' )

# Split the data into features and labels
X = data.drop( 'label' , axis= 1 )
y = data[ 'label' ]

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size= 0.2 , random_state= 42 )
在此示例中,我们首先将 CSV 文件“data.csv”读入 DataFrame。然后,我们将数据拆分为特征 X 和标签 y,其中 X 包含除“标签”列之外的所有列,而 y 仅包含“标签”列。

接下来,我们使用 train_test_split() 函数将数据拆分为训练集和测试集。我们传递特征 X 和标签 y,指定所需的测试大小(例如,20% 的测试集为 0.2),并设置随机状态以实现可重复性。

拆分数据后,我们可以使用训练集(X_train 和 y_train)来训练我们的机器学习模型并评估其在测试集(X_test 和 y_test)上的性能。

这些是使用 Python 中的 Pandas 库进行机器学习的一些基本数据处理技术。请记住,数据预处理和准备是机器学习管道中必不可少的步骤,根据项目的具体要求,还有更多可用的技术和工具。

 

5.2 基本数据处理(L05:使用 Scikit-Learn 进行机器学习)



5.2 基本数据处理(L05:使用 Scikit-Learn 进行机器学习)

在上一个视频中,我们讨论了如何将表格文本文件作为数据集读取。具体来说,我们专注于处理 CSV 文件,更具体地说,是 Iris 数据集。我们将 Iris 数据集从 CSV 文件导入到 Pandas DataFrame 中。

在本视频中,我们将深入研究如何使用 scikit-learn 为机器学习准备适当格式的数据。我们将探索使用 Pandas 和 NumPy 将数据转换为适合机器学习的格式的基本数据处理技术。但在我们继续之前,让我们简要回顾一下 Python 函数的概念,因为当我们讨论在 Pandas DataFrame 中转换值时它会派上用场。

这里我们有一个简单的 Python 函数,称为“some_func”。它采用单个输入参数“x”并将其转换为字符串。然后它将转换后的值与固定字符串“hello world”连接起来。如果我们提供一个整数(例如 123)作为输入,它将被转换为一个字符串(“123”)并与“hello world”连接起来,从而产生最终的字符串。这是 Python 函数工作原理的基本概述,其中冒号表示函数的主体,返回语句指定输出。虽然函数内可以有多行代码,但 return 语句标志着结束。

另一个值得一提的概念是 lambda 函数。 Lambda 函数是一种无需显式命名即可定义小函数的简写方式。当需要节省代码行和快速编写函数时,通常会使用它们。在 Pandas 列中的数据转换上下文中,经常使用 lambda 函数。虽然 lambda 函数提供了更简洁的语法,但它们基本上执行与常规函数相同的操作。当与 Pandas DataFrame 列上的 apply 方法结合使用时,它们特别有用。

在上一课中,我们将 Iris 数据集从 CSV 文件读入 Pandas DataFrame。 Iris 数据集包含 150 行,但为简洁起见,我们只显示前五行。数据集包括一个 ID 列,这不是必需的,后面是设计矩阵 X 表示的特征。我们还有类标签,通常表示为 y。传统上,scikit-learn 和其他库不会将字符串变量作为类标签处理,因此通常的做法是将它们转换为整数。例如,“Iris setosa”将转换为整数 0,“Iris versicolor”转换为 1,“Iris virginica”转换为 2。这种转换是必要的,因为许多算法被设计为使用整数类标签而不是字符串标签。

但是,scikit-learn 现在在大多数函数中都支持字符串类标签,无需进行显式转换。在内部,转换是自动处理的。尽管如此,有些工具可能无法正确处理字符串数据,因此仍然建议将类标签转换为整数。通过这样做,您可以确保与各种工具的兼容性并减少遇到错误的可能性。

为了说明转换过程,我们将结合 apply 方法使用 lambda 函数。通过将 lambda 函数应用于 DataFrame 的物种列,我们可以将字符串类标签转换为整数标签。但是,值得一提的是,使用映射字典通常是更好的方法。它提供了更好的可读性,并允许更轻松地解释类标签转换。此外,如果您以后需要检索原始类标签,您可以定义一个反向字典并使用它将整数标签映射回它们的原始字符串表示形式。

为了演示转换,我们将数据集重新加载到其原始状态。然后,我们不使用 apply,而是使用 map 函数使用映射字典将字符串标签转换为整数。我们还展示了 values 属性的使用,它访问底层的 NumPy 数组。使用 NumPy 数组。

出于多种原因,使用 NumPy 数组可能是有益的。与 Pandas DataFrames 相比,NumPy 数组的内存效率更高,使其成为大型数据集的理想选择。此外,scikit-learn 中的许多机器学习算法都希望输入数据采用 NumPy 数组的形式。

要将我们的 Pandas DataFrame 转换为 NumPy 数组,我们可以简单地访问 DataFrame 的 values 属性。让我们看一个例子:

import pandas as pd
import numpy as np

# Reload the Iris dataset
iris_df = pd.read_csv( 'iris.csv' )

# Convert the features (X) into a NumPy array
X = iris_df.drop([ 'species' ], axis= 1 ).values

# Convert the class labels (y) into a NumPy array
y = iris_df[ 'species' ].values
在此示例中,我们使用 DataFrame 的 drop 方法删除“物种”列并将特征作为 DataFrame 获取。然后,通过访问 values 属性,我们将特征转换为 NumPy 数组并将其分配给变量 X。

同样,我们使用索引运算符 [] 访问 DataFrame 的“物种”列,并将其转换为 NumPy 数组,并将其分配给变量 y。

现在,X 变量包含作为 NumPy 数组的特征矩阵,而 y 变量包含作为 NumPy 数组的类标签。我们可以使用这些数组作为各种机器学习算法的输入。

假设我们要将数据集拆分为训练集和测试集以进行模型评估。 Scikit-learn 提供了一个名为 train_test_split 的实用函数,可以简化此任务。这是一个例子:

 from sklearn.model_selection import train_test_split

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size= 0.2 , random_state= 42 )
在此示例中,我们从 sklearn.model_selection 模块导入 train_test_split 函数。我们将 X 和 y 数组作为参数传递给函数,同时传递指定要分配给测试的数据集比例的 test_size 参数(在本例中为 20%)。 random_state 参数确保拆分的可重复性。

调用 train_test_split 后,我们得到四个数组:X_train 和 y_train 包含训练数据,而 X_test 和 y_test 包含测试数据。

现在您可以使用 X_train 和 y_train 数组来训练您的机器学习模型并使用 X_test 和 y_test 数组评估其性能。

综上所述,通过将 Pandas DataFrame 转换为 NumPy 数组,我们可以利用 NumPy 的优势,例如内存效率和与机器学习算法的兼容性。此外,scikit-learn 还提供了方便的函数,例如 train_test_split,用于将数据拆分为训练集和测试集。

 

5.3 面向对象编程和 Python 类(L05:使用 Scikit-Learn 进行机器学习)



5.3 面向对象编程和 Python 类(L05:使用 Scikit-Learn 进行机器学习)

在下一讲深入探讨使用 scikit-learn 进行机器学习的主题之前,让我们花点时间讨论一下面向对象的编程,特别是 Python 类。理解类将是高度相关的,因为 scikit-learn 严重依赖于面向对象的编程概念。在本视频的最后,我将演示使用 scikit-learn API 实现 K 最近邻,这是 scikit-learn 用于实现分类器等估计器的方法。

那么,让我们从讨论 Python 类开始。为了更好地理解 scikit-learn API,了解类的基础知识很重要。简单来说,类可以被认为是创建对象的蓝图。对象是一个类的实例,可以可视化为用于制作饼干的相同饼干模具形状的不同变体。该类本身充当 cookie 切割器模板,而 cookie 代表从该类创建的对象。

在 Python 中,我们使用 class 关键字定义一个类,后跟类名。在类内部,我们定义了不同的类方法。类方法类似于函数,但它们有一个强制性的第一个参数,称为 self,它指的是对象本身。这个 self 参数允许我们访问对象的属性和方法。换句话说,它使我们能够与对象的数据和行为进行交互。

在车辆示例的上下文中,让我们考虑一个简单的原始车辆类。此类代表不同类型的车辆,例如汽车、摩托车或卡车。该类有多种方法来定义其行为。第一个方法是 __init__ 方法,也称为构造函数。当从类创建新对象时,会自动执行此方法。它接受 self 参数和初始化对象所需的任何其他参数。

在 __init__ 方法中,我们定义了一个名为 horsepower 的属性,它被分配了作为参数提供的值。该属性表示车辆的马力。创建新对象时,它将具有一个马力属性,可以访问该属性以检索马力值。

除了__init__方法之外,我们还可以定义其他修改对象属性的方法。例如,tune_motor 方法将车辆的马力属性加倍,模拟电机调校。通过在车辆对象上调用此方法,其马力属性将相应修改。

此外,我们可以定义基于对象属性返回值的方法。在示例中,horsepower_to_torque 方法根据对象的马力和提供的 RPM 值计算扭矩值。此方法演示了如何利用对象的属性来执行计算并返回有用的结果。

值得注意的是,在 Python 中,有指示方法可见性的约定。带有单个下划线前缀的方法,例如 _private_method,被认为是私有的,不打算由该类的用户直接使用。但是,用户仍然可以访问和调用这些方法,尽管通常不鼓励这样做。带有双下划线前缀的方法,例如 __very_private_method,甚至更受限制,需要特定的语法才能访问它们。

此外,Python 支持类继承,允许我们创建从父类继承属性和方法的子类。这个概念使我们能够创建具有附加属性和行为的专用类,同时利用父类中定义的现有功能。例如,我们可以创建一个专门的 Car 类,它继承自 Vehicle 类并添加一个专门用于汽车的 number_of_wheels 属性。

为了说明所讨论的概念,提供了 K 最近邻分类器的示例。此实现遵循 scikit-learn API 约定,并演示了 scikit-learn 中估算器类的使用。这是一个简化的实现:

 class KNNClassifier:

    def __init__( self , k):
         self .k = k
         self .X_train = None
         self .y_train = None
    
    def fit( self , X_train, y_train):
         self .X_train = X_train
         self .y_train = y_train
    
    def predict( self , X_test):
        predictions = []
         for x in X_test:
            distances = []
             for i, x_train in enumerate( self .X_train):
                distance = self ._calculate_distance(x, x_train)
                distances.append((distance, self .y_train[i]))
            distances.sort()
            k_nearest = distances[: self .k]
            prediction = self ._majority_vote(k_nearest)
            predictions.append(prediction)
         return predictions
    
    def _calculate_distance( self , x1, x2):
         # Calculate the distance between two data points
         # (e.g., Euclidean distance)
        pass
    
    def _majority_vote( self , neighbors):
         # Determine the majority class among the nearest neighbors
        pass

在此示例中,KNNClassifier 是表示 K 最近邻分类器的类。构造函数采用参数 k,它指定要考虑的最近邻居的数量。

fit 方法用于训练分类器。它有两个参数:X_train(训练数据)和 y_train(相应的标签)。该方法只是将训练数据和标签存储在对象的属性中以备后用。

predict 方法用于对新数据进行预测。它以 X_test(测试数据)作为参数并返回测试数据的预测标签。对于 X_test 中的每个数据点,该方法使用 _calculate_distance 方法计算到训练集中所有数据点的距离。然后它选择 k 个最近的邻居并使用 _majority_vote 方法确定多数类。预测标签附加到预测列表。

_calculate_distance 方法是一种私有方法(由前导下划线表示),用于计算两个数据点之间的距离。这可以是欧几里德距离或适合该问题的任何其他距离度量。

_majority_vote 方法是另一种私有方法,用于确定一组邻居中的多数类。这可以通过计算每个类标签的出现次数并选择计数最高的标签来完成。

此示例演示了 scikit-learn 中估计器类的基本结构。当然,scikit-learn 在 KNeighborsClassifier 类中提供了更复杂和优化的 K 最近邻实现,但这个简化版本说明了基本原理。

 

5.4 Scikit-learn 简介(L05:使用 Scikit-Learn 进行机器学习)



5.4 Scikit-learn 简介(L05:使用 Scikit-Learn 进行机器学习)

在这个相对较短的视频中,目标是使用 scikit-learn 介绍机器学习。 Scikit-learn 是 Python 中广泛使用的机器学习库,它为各种机器学习任务提供了一套全面的工具和算法。虽然您之前可能在 k 最近邻 (KNN) 讲座的上下文中看过 scikit-learn,但本视频旨在退后一步并正确介绍该库。

在这个简短的视频之后,将有一个更长的视频更深入地介绍如何使用 scikit-learn 准备训练数据集。与传统方法相比,这将涵盖使数据准备更加方便和高效的技术和工具。

在随后的视频中,我们将探索 scikit-learn 中的一些很酷的概念,例如结合预处理技术、机器学习分类器拟合和训练,使用 scikit-learn 管道。这允许更简化和高效的工作流程。

现在,让我们更详细地讨论使用 scikit-learn 进行机器学习。 Scikit-learn 因其良好的声誉、庞大的用户群和用户友好的特性而被广泛认为是 Python 的主要机器学习库。它是一个设计良好的库,提供一致且直观的 API。 Scikit-learn 也得到积极维护和定期更新,众多贡献者使其成为机器学习任务的强大而可靠的选择。

需要注意的是,scikit-learn 主要侧重于传统的机器学习技术,并不适用于深度学习。深度学习是一个独立的领域,拥有自己的专业库。对于深度学习,通常使用 TensorFlow 或 PyTorch 等其他库。然而,对于传统的机器学习任务,scikit-learn 通常是首选库。

Scikit-learn 已经存在了一段时间,它的首次发布可以追溯到 2007 年。尽管年代久远,它仍然是一个受欢迎且积极维护的库。它最初是 David Cournapeau 的 Google Summer of Code 项目,随着时间的推移获得了许多其他开发人员的贡献。 GitHub 上有超过 1,875 名贡献者和近 150,000 名用户,很明显,scikit-learn 是一个备受推崇的库,拥有大量的社区支持。

您可以找到 scikit-learn 的官方网站,其中包括文档、教程和其他有用的资源。如果您在研究项目中使用 scikit-learn,最好引用该库作为参考,承认在其开发中付出的努力。

要了解 scikit-learn 的 Estimator API,让我们深入研究它的主要组件。 Estimator API 用于监督学习任务,包括用于回归分析的回归器和用于分类任务的分类器。使用 scikit-learn 时,您通常使用特定的超参数初始化估计器,这些超参数在类的构造函数中设置。

拟合过程对于估算器至关重要。初始化完成后,需要调用fit方法,提供训练数据(特征)及其对应的标签。 fit 方法在给定数据上训练估计器,使其能够在以后进行预测。在拟合过程中,某些属性被分配给估计器,用尾部下划线表示,表示它们是在模型拟合期间创建的。

拟合模型后,您可以使用预测方法对新数据进行预测。 predict 方法将测试数据(与训练数据具有相同的特征)作为输入并返回预测标签。

此外,scikit-learn 提供了一种计算模型性能的评分方法。对于分类器,它通常代表准确率,而对于回归器,它通常计算确定系数(R^2 分数)。该方法是评估模型性能的便捷方式。

除了这些核心组件之外,scikit-learn 还提供了广泛的预处理技术和实用程序来增强您的机器学习工作流程。

机器学习的一个重要方面是数据预处理,它涉及将原始数据转换为适合训练模型的格式。 Scikit-learn 提供了各种预处理模块,可以处理特征缩放、处理缺失值、编码分类变量等任务。

例如,StandardScaler 类可用于通过减去均值和缩放到单位方差来标准化特征。这在处理具有不同比例的特征时很重要,因为它有助于算法更快地收敛并产生更准确的结果。

另一种有用的预处理技术是处理缺失值。 SimpleImputer 类提供了用合适的替代方案替换缺失值的策略,例如使用相应特征的平均值、中值或最频繁的值。

在处理分类变量时,scikit-learn 提供了 OneHotEncoder 和 LabelEncoder 类。 LabelEncoder 将分类标签转换为数值,而 OneHotEncoder 将分类特征转换为二进制向量表示,使算法能够有效地处理分类数据。

为了简化您的机器学习工作流程,scikit-learn 提供了一个名为管道的强大工具。管道将多个预处理步骤和机器学习模型组合到一个对象中,从而更容易一致地管理和应用整个工作流。

管道确保相同的预处理步骤一致地应用于训练和测试数据集,避免数据泄漏和潜在错误。它们还简化了部署过程,因为您可以保存整个管道对象并将其重新用于新数据,而无需担心单独的预处理步骤。

通过使用 scikit-learn 的管道功能,您可以将多种预处理技术(例如缩放、输入缺失值和编码分类变量)与所需的机器学习模型链接在一起。这会带来更加精简和高效的工作流程,使您能够专注于机器学习项目的核心方面。

Scikit-learn 支持广泛的机器学习算法,包括线性回归、逻辑回归、支持向量机、决策树、随机森林、梯度提升等等。每个算法都实现为具有一致方法(例如拟合、预测和评分)的估计器类。

为了为您的任务选择合适的算法,scikit-learn 提供了各种用于模型选择和评估的工具。这些包括交叉验证、超参数调整和模型评估指标的技术。交叉验证通过将数据拆分为多个训练测试拆分、在数据的不同子集上训练和评估模型来帮助评估模型的性能。

超参数调整涉及找到模型超参数的最佳值,这些参数不是从数据中学习的,而是在训练前设置的。 Scikit-learn 提供了网格搜索和随机搜索等方法来自动执行搜索最佳超参数值的过程。

模型评估指标,如准确性、精确度、召回率、F1 分数和 ROC 曲线下面积,对于评估模型在不同任务上的性能至关重要。 Scikit-learn 提供了广泛的此类指标,可以轻松计算和比较。

Scikit-learn 是一个功能强大且流行的 Python 机器学习库,它为各种机器学习任务提供了广泛的工具和算法。其用户友好的 API、广泛的文档和活跃的社区使其成为初学者和经验丰富的从业者的绝佳选择。无论您是需要预处理数据、构建管道、选择模型还是评估性能,scikit-learn 都能提供您高效完成工作所需的工具。