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

 

2.4 K近邻之大O(L02: Nearest Neighbor Methods)



2.4 K近邻之大O(L02: Nearest Neighbor Methods)

现在,让我们深入探讨运行时复杂性这一主题,特别关注大 O 表示法和 k 最近邻 (KNN) 算法的运行时复杂性。

大 O 表示法是计算机科学中用于分析算法效率的概念。它主要指的是运行时复杂度,它决定了算法的执行速度如何随着输入大小的增加而变化。此外,Big O 表示法还可以用于分析算法的内存效率,指示其执行所需的内存量。

对于 KNN,训练步骤涉及保存训练数据集,这可能会占用大量内存。存储大型训练数据集可能需要大量 RAM 或硬盘驱动器存储空间。虽然存储空间随着时间的推移变得越来越便宜,但在处理海量数据集(例如数百万张图像)时仍然存在局限性。

但是,让我们将注意力转移到预测步骤中 KNN 的运行时复杂性上。在我们继续之前,让我们简单介绍一下大 O 表示法。它是一种用于描述算法效率的符号,通常用函数表示。这些函数表示算法的运行时复杂度,常见示例包括 O(1)(常数)、O(log n)(对数)等。这些函数指示算法的运行时间如何随输入大小 (n) 缩放。

为了更好地理解运行时复杂性,我们可以按效率的升序排列函数,从 O(1) 到指数复杂度。在这种情况下,常数函数是理想的,因为它不受输入大小的影响,确保一致的执行速度。对数函数和线性函数也很有效,尽管不如常数函数理想。然而,随着复杂度增加到二次、三次和指数,算法的效率显着下降。指数复杂度特别有害,应该避免,尤其是在机器学习中处理大型数据集时。

为了根据 n(输入大小)可视化运行时复杂性,可以创建一个图,其中 x 轴表示 n,y 轴表示算法的复杂性。随着 n 的增加,某些函数表现出越来越差的性能。必须避免具有高复杂性的算法,例如二次、三次或指数,因为它们会导致执行时间过长。

现在,让我们探讨如何推导出给定函数的大 O 表示法。例如,考虑二次函数 f(x) = ax^2 + bx + c。在推导大 O 符号时,我们关注增长最快的主导项。在这种情况下,主导项是 x^2。因此,此函数的大 O 表示法为 O(x^2),表示二次复杂度。

让我们考虑另一个函数来进一步说明这个过程。假设我们有一个函数 f(x) = ax(log x)。同样,我们确定主导项,即 x(log x)。在这里,我们忽略常数因子 a 并关注 x(log x) 项。因此,此函数的大 O 表示法为 O(x log x),表示对数线性复杂度。

值得一提的是,对数的底数(例如,以 2 为底的对数或自然对数)不会影响大 O 表示法。不同的基只引入了一个比例因子,在确定运行时复杂度时可以忽略。因此,为简单起见,我们通常考虑不指定底数的自然对数(log)。

为了进一步巩固您的理解,让我们检查一个用于矩阵乘法的 Python 函数,演示大 O 表示法在计算算法中的应用。该函数在两个矩阵 A 和 B 之间执行矩阵乘法。尽管为了便于说明,该实现故意效率低下,但它允许我们分析其运行时复杂性。

该函数首先初始化一个大小为 nxn 的空矩阵 C,其中 n 是输入矩阵的维数。然后,它遍历矩阵 A 的每一行 i 和矩阵 B 的每一列 j。在嵌套循环中,它计算矩阵 A 的行 i 和矩阵 B 的列 j 的点积,并将结果存储在对应的单元格中矩阵 C。

下面是矩阵乘法函数的 Python 代码:

def matrix_multiplication(A, B):
    n = len(A)  # Assuming square matrices of size n x n
    C = [[ 0 ] * n for _ in range(n)]  # Initialize matrix C
    
     for i in range(n):
         for j in range(n):
             for k in range(n):
                C[i][j] += A[i][k] * B[k][j]  # Calculate dot product and update C[i][j]
    
    return C
为了分析这个函数的运行时复杂度,我们来分解一下。外层循环迭代 n 次,表示矩阵 A 的行。第二个循环也迭代 n 次,表示矩阵 B 的列。在这些循环内部,还有一个嵌套循环也迭代 n 次,表示点积计算。因此,整体复杂度为 O(n^3),表示三次复杂度。

请务必注意,三次复杂度并不理想,尤其是对于较大的 n 值。随着输入大小的增加,该函数的执行时间显着增加。因此,对于更大的矩阵,应该使用更有效的算法来执行矩阵乘法,例如 Strassen 算法或其他实现更好的运行时复杂度的优化方法,例如 O(n^2.81)。

总之,了解算法的运行时复杂性(用大 O 表示法表示)对于评估其效率和可扩展性至关重要。它使我们能够随着输入大小的增加来估计算法的性能,从而使我们能够为不同的场景选择最合适的算法,并避免针对大型数据集的低效算法。

 

2.5 改进k-近邻(L02: Nearest Neighbor Methods)



2.5 改进k-近邻(L02: Nearest Neighbor Methods)

在本视频中,我们将深入探讨通过对超参数进行某些修改和考虑来改进 K 最近邻算法的主题。在之前的视频中,我们讨论了使用优先级队列作为数据结构来提高寻找最近邻居的效率。这个优先级队列有助于避免为每个新邻居搜索整个训练集。

现在,让我们探索另一种利用空间划分数据结构来提高 K 最近邻算法计算性能的方法。一种这样的数据结构是堆,它用作空间分区结构以加快对训练示例的搜索过程。通过将数据集划分为数据结构中的子集,我们可以最大限度地减少对每个训练数据点进行距离计算的需要。

一种空间划分方法称为分桶。这涉及根据特定标准将数据集划分为子集或桶,例如大小相同的桶或由特征测量定义的边界。通过这样做,我们可以避免搜索整个训练集,并在寻找查询点的邻居时只关注特定桶内的相关点。这种优化显着提高了搜索过程的效率。

另一种空间划分技术是 KD 树,它构造超立方体来划分数据集。这种方法不同于分桶,但其共同目标是通过减少距离计算次数来提高搜索效率。 KD 树特别适用于具有大量特征的数据集。

类似地,球树算法创建超球体作为空间分区。 KD 树和球树之间的选择取决于数据集的特征。对于高维数据集,球树算法通常是首选。值得注意的是,广泛使用的 scikit-learn 机器学习库为 K-最近邻分类器的算法提供了不同的选项,可以根据数据集自动选择最有效的空间划分算法。但是,如果需要,您可以手动覆盖此设置。

此外,我们可以通过采用降维技术来提高 K 最近邻的性能。降维有两种形式:特征提取和特征选择。特征提取涉及转换或组合现有特征以创建数据的低维表示。另一方面,特征选择涉及选择可用特征的子集而不创建新特征。通过减少特征数量,我们可以降低距离计算的计算成本,并有可能提高算法的效率。此外,高维数据集经常遭受维数灾难,这可能会由于过度拟合而导致泛化性能不佳。因此,降维也可以帮助缓解这个问题。

为了优化 K 最近邻的计算性能,我们可以探索编辑或修剪技术。修剪涉及在不影响决策边界的情况下从训练集中删除不必要的数据点。通过消除冗余点,我们可以减少比较和距离计算的次数,使算法更加高效。同样,创建原型涉及用单个代表点替换训练数据点的密集区域。该策略减少了存储空间需求,同时保持了算法的预测准确性。

此外,超参数调整在提高 K 最近邻算法的预测性能方面起着至关重要的作用。超参数是影响算法行为但不是从训练数据中学习的可调设置。它们包括 K 值(要考虑的邻居数量)、特征缩放、使用的距离度量以及距离计算的加权方案。为这些超参数选择合适的值可以显着影响算法的性能。但是,必须谨慎并避免使模型过度拟合训练数据。

通过利用空间分区数据结构、采用降维技术、应用编辑和修剪方法以及微调超参数,我们可以增强 K 最近邻算法的计算和预测性能。

 

2.6 Python中的K近邻(L02: Nearest Neighbor Methods)



2.6 Python中的K近邻(L02: Nearest Neighbor Methods)

在对 K 最近邻进行全面讨论后,本文继续提供一个 Python 示例,展示了使用流行的 scikit-learn 库实现 K 最近邻。作者承认并非所有方面都可以立即清楚,并向读者保证未来的讲座将更深入地探讨 Python、NumPy 和 scikit-learn。尽管如此,所提供的示例可作为预告片,提供有关这些工具如何运作的自上而下的视角。

为了支持实现示例,作者参考了一个网站,读者可以在该网站上找到代码示例。此外,作者还解释了使用 zip 文件或克隆从 GitHub 下载存储库的过程。强调 GitHub 作为现实世界工具的重要性,作者建议拥有 GitHub 个人资料和共享项目可以有利于向潜在雇主展示一个人的工作。

文本继续提供有关如何使用 GitHub 链接和“git clone”命令克隆存储库的详细说明。虽然承认 Windows 用户的过程可能略有不同,但作者建议寻求教程或 TA(助教)的帮助。成功克隆存储库后,作者将指导读者导航到该文件夹,并说明可以使用“git pull”命令获取更新。

转到代码示例,作者演示了打开 Jupyter Notebook,具体为 Jupyter Lab,并逐步执行命令。为了避免让读者不知所措,作者强调了每次执行后清除输出的重要性。此外,作者提到了 Jupyter Notebooks 中水印扩展的用处,它显示了所使用的软件包的版本。此信息有助于故障排除并确保结果的可复制性。安装了 Pandas、NumPy、Matplotlib 和 scikit-learn 等基本软件包,以方便实施。

接下来,作者从 CSV 文件加载 Iris 数据集,并展示了使用“head”和“tail”等命令来预览数据集。使用“read_csv”函数将数据加载到 Pandas DataFrame 中。虽然注意到机器学习通常使用 NumPy 数组,但作者强调 scikit-learn 也支持数据帧。为了说明这一点,作者提供了一个从 DataFrame 中提取特定列以创建 NumPy 数组的示例。数组的形状,指示训练示例和特征的数量,使用“shape”命令显示。

该文本概述了使用 Python 和 scikit-learn 库构成机器学习工作流的一系列步骤。以下是这些步骤的详细摘要:

  1. 打乱索引和标签:作者通过讨论在数据集中打乱索引和标签的过程来启动工作流程。混洗的目的是随机化数据点的顺序,确保每个标签对应于特征矩阵中的正确行。

  2. 数据集划分:将数据集划分为训练集和测试集。作者手动选择前105个例子作为训练集,保留剩下的45个例子作为测试集。这种划分对于评估机器学习模型的性能至关重要。

  3. Introduction to scikit-learn and the Iris Dataset:作者介绍了scikit-learn库,具体介绍了Iris数据集的实现和“train_test_split”函数。 Iris 数据集是一种广泛用于分类任务的流行数据集。 “train_test_split”函数自动打乱数据集并将其拆分为指定的比例以进行训练和测试。

  4. Visualization Using a Scatterplot Matrix:作者提供了一个名为“scatterplot matrix”的便捷函数来可视化数据集。此函数利用 matplotlib 库创建一个散点图矩阵,其直方图显示在对角线上。散点图矩阵直观地表示数据集中不同特征之间的关系。

  5. Demonstration of Scatterplot Matrix:作者通过绘制Iris数据集来演示散点图矩阵的用法。分配不同的颜色来代表不同类别的花。值得注意的是,作者强调特定特征(例如花瓣长度和花瓣宽度)对于区分不同的花类特别有用。

  6. k-最近邻 (k-NN) 分类器简介:作者继续解释 k-最近邻 (k-NN) 分类器,这是一种根据数据点与相邻数据点的接近程度对数据点进行分类的简单算法。为了实例化 k-NN 分类器,作者创建了一个具有三个邻居的对象。

  7. 拟合 k-NN 分类器:使用“拟合”方法将 k-NN 分类器拟合到训练集。此步骤使用提供的训练数据训练模型。

  8. 对测试集的预测:作者使用拟合的 k-NN 分类器使用“预测”方法对测试集进行预测。预测存储在名为“pred”的变量中。

  9. 性能评估:为了评估模型的性能,作者将预测标签(存储在“pred”中)与测试集的真实标签(存储在“y_test”中)进行比较。通过计算正确预测的数量,可以确定模型在测试集上的准确性。

  10. 结论和进一步探索:本讲座最后鼓励读者探索 scikit-learn 文档,以获取有关 k 最近邻算法及其各种选项的更多信息。此外,作者向读者提出了一个关于 k-NN 分类器使用的默认距离度量的问题,并建议了一个调查和讨论这方面的练习。

该讲座对各种主题进行了全面的解释,包括 K 最近邻的概念、使用 scikit-learn 库的示例实现、从 GitHub 下载和克隆存储库的指南、Jupyter Notebook 和 Jupyter Lab 的介绍、加载数据集放入 Pandas DataFrame,并演示列的提取和到 NumPy 数组的转换。

 

3.1(可选)Python概览



3.1(可选)Python概览

我希望到目前为止你们都度过了愉快的一周并享受讲座。今天,我想讨论一下最近讲座中涉及的几个重要主题。

首先,我们有一个关于改进 Canaan 的讲座,然后是一个关于使用 psychic learn 在 Python 中实现 kin 的讲座。根据你对“了解你”测验的介绍的反馈,我发现你们中的大多数人都有编程背景或之前参加过编程课程。这是个好消息,因为它将对您在本课程中非常有益。但是,我注意到只有大约一半的人对 Python 有扎实的经验。因此,在我们使用 Python 深入研究科学计算并更详细地探索心理学习之前,我认为为那些刚接触 Python 的人提供一些设置 Python 的帮助会有所帮助。这将确保下一堂课对每个人来说都能更顺利地进行。

轻松一点,我真的很喜欢阅读有关您最喜爱的爱好的文章。看来你们中的许多人都和我一样热爱越野滑雪、跑步和徒步旅行等户外活动。在大自然中度过时光真的让人耳目一新,尽管我知道下雨天和漫长的冬天会限制这些机会。你们中的一些人还提到了对电子游戏的兴趣,一位学生甚至提到了塞尔达系列。我必须承认,我也是该系列的忠实粉丝,喜欢在下雪的圣诞节或忙碌的一天后放松身心。

继续,正如所承诺的,今天的讲座将是可选的。如果您已经拥有丰富的 Python 经验并在您的计算机上安装了 Python,则可以跳过以下三个视频。但是,如果您是 Python 的新手或在设置方面需要帮助,我建议您观看它们。这些视频将根据我自己的 Python 经验为您提供动力和实用建议。请务必注意,您无需成为专家级程序员即可在本课程中使用 Python。我们将专注于机器学习所需的基础知识,随着我们的进步,您将学到更多。

下周,我们将有第一个真正的家庭作业,您将在其中实现 K 最近邻算法。除了使用通灵学习之外,此作业还需要您编写自己的代码。因此,本周设置 Python 以准备作业将对您有所帮助。不用担心;该作业旨在帮助您更好地理解 KNN 算法,并且它不会太难,因为它是第一个作业。完成这项任务后,我们将更深入地研究概念机器学习方面。

在继续进行之前,让我们快速了解一下课程进度。在第一周,我们介绍了机器学习和 K 最近邻。目前,我们处于第二周,重点是计算基础。这些基础至关重要,因为我们稍后将使用它们来实现各种机器学习概念。因此,尽早熟悉 Python 及其用法非常重要。在本讲座中,我们将主要讨论 Python 以及如何设置它。请注意,我将在我的 Mac 上演示设置过程,但我们的助教可以协助解决任何与 Windows 相关的问题。

Python 是一种解释型动态编程语言,与 C 或 C++ 等静态类型语言相比,它更具交互性和用户友好性。虽然 Python 可能比这些语言慢,但对于我们的目的来说这并不是一个重要的问题。我们将在下一课中探讨的许多科学计算库都是用 C 或 Fortran 语言编写的,并提供快速的执行时间。 Python 是一种通用编程语言,广泛用于各种应用程序,包括 Django 等 Web 框架和 Instagram 和 Dropbox 等流行服务。

现在,让我们通过编写一个简单的程序,将 Python 与 C 等静态类型语言进行比较。在 C 中,我们需要声明变量并显式指定它们的数据类型,例如整数、浮点数或字符。这是一个简单的 C 程序示例:

#include <stdio.h>

int main() {
     int age = 25 ;
     float height = 1.75 ;
     char initial = 'J' ;

    printf( "My age is %d\n" , age);
    printf( "My height is %.2f meters\n" , height);
    printf( "My initial is %c\n" , initial);

     return 0 ;
}
在这个 C 程序中,我们用各自的数据类型声明了变量 age、height 和 initial。然后我们为这些变量赋值并使用 printf() 打印它们。

现在,让我们比较一下 Python 中的同一个程序:

age = 25
height = 1.75
initial = 'J'

print( "My age is" , age)
print( "My height is" , height, "meters" )
print( "My initial is" , initial)
在 Python 中,您不需要显式声明变量类型。你可以直接给变量赋值,Python会自动推断数据类型。 print() 函数用于显示输出。

Python 的简单性和可读性使其成为初学者和经验丰富的程序员的绝佳选择。它拥有庞大的库和框架生态系统,使其适用于科学计算、数据分析、机器学习等。

现在,让我们继续在您的计算机上设置 Python。有多种安装 Python 的方法,但我推荐使用 Anaconda 发行版,它预装了许多用于科学计算的有用库。以下是安装 Anaconda 的步骤:

  1. 访问 Anaconda 网站 ( https://www.anaconda.com/products/individual ) 并下载适用于您的操作系统(Windows、macOS 或 Linux)的安装程序。

  2. 运行安装程序并按照屏幕上的说明进行操作。除非您有特定的偏好,否则您可以选择默认安装选项。

  3. 安装完成后,您应该在计算机上安装了 Anaconda Navigator 和 Anaconda Prompt(或 Anaconda PowerShell Prompt)。这些是用于管理 Python 环境和包的便捷工具。

  4. 打开 Anaconda Navigator 并单击“环境”选项卡。在这里,您可以为本课程创建一个新环境。单击“创建”按钮,为环境命名(例如“机器学习”),然后选择 Python 版本(最好是 Python 3.x)。单击“创建”以创建环境。

  5. 创建环境后,单击 Anaconda Navigator 中的“Home”选项卡。您应该会看到可用应用程序和环境的列表。从窗口顶部的下拉菜单中选择您新创建的环境。

  6. 在“主页”选项卡中,单击 Jupyter Notebook 部分下的“安装”按钮。这将安装 Jupyter Notebook,我们将使用它进行交互式编程和运行 Python 代码。

  7. 安装后,单击 Jupyter Notebook 旁边的“启动”按钮。这将在您的 Web 浏览器中打开一个新选项卡,运行 Jupyter Notebook。

恭喜!您已经使用 Anaconda 发行版成功安装了 Python 和 Jupyter Notebook。您现在已准备好开始使用 Python 编写本课程的代码。在下一课中,我们将深入探讨使用 Python 进行科学计算,并探索名为 scikit-learn 的流行库。

如果您在安装过程中遇到任何问题或有任何疑问,请随时在论坛中提问或联系助教寻求帮助。

请注意,这些说明特定于 Anaconda,但如果您更喜欢使用不同的 Python 发行版,例如 Miniconda 或标准 Python 发行版,您仍然可以继续学习本课程。

 

3.2(可选)Python设置


3.2(可选)Python设置

在课程的第二个视频中,我们将讨论设置过程以及如何安装 Python。在上一个视频中,我们介绍了解释型和动态编程语言的基础知识,重点介绍了 Python 作为一种动态解释型语言。

在我们继续安装之前,请务必观看视频并避免在观看时在您的计算机上安装任何东西。此预防措施可确保您在做出决定之前完全了解不同的安装选项。在没有适当知识的情况下安装软件可能会导致以后后悔。

首先,建议检查您的计算机上是否已经安装了最新的 Python 版本。在 Mac 或 Linux 上,您可以使用“which Python”命令来确定安装位置和版本。同样,在 Windows 上,您可以使用“where”命令来查找安装位置。

许多 Mac 传统上都带有过时版本的 Python,特别是 Python 2。强烈建议更新 Python,因为 Python 社区不再支持 Python 2。理想情况下,建议安装 Python 3.8 或 3.7,因为较新的 3.9 版本仍在开发中。

安装 Python 的官方方法是访问 python.org 并下载安装程序。但是,通常首选的替代方法是使用 Anaconda,或者更具体地说,Miniconda。 Miniconda 是 Anaconda 的轻量级版本,不包含不必要的库,可节省计算机上的存储空间。虽然 Anaconda 带有预安装的库,但 Miniconda 允许更自定义的安装过程。

就个人而言,讲师推荐使用 Miniconda,因为它的便利性和 Python 科学计算社区的许多成员对它的积极体验。 Miniconda 提供了一个全面的包管理器,可确保安装所有必需的包版本并管理包依赖性。此功能使维护稳定和兼容的开发环境变得更加容易。

要安装 Miniconda,您可以访问文档网站 docs.conda.io,然后导航至最新的英文版 Miniconda 安装页面。从那里,您可以为您的操作系统选择合适的安装程序。对于 Mac 用户,通常使用 bash 安装程序。下载安装程序后,执行脚本,接受许可协议,选择安装位置。

安装 Miniconda 后,您可以通过打开 Python shell 检查您的默认 Python 版本,它现在应该显示更新的版本。 Miniconda 还提供了管理不同环境的工具,允许您为不同的项目创建隔离的环境。虽然本课程不是必需的,但如果您同时处理多个项目,这些环境会很有用。

要安装软件包,例如下一课所需的“numpy”软件包,您可以使用软件包管理器“pip”或 Conda 安装程序。由于您使用的是 Miniconda,因此建议尽可能使用 Conda 安装程序,因为它可以确保更好的兼容性和版本管理。但是,如果某个包在 Conda 中不可用,您可以求助于使用“pip”。

如果您需要安装 Conda 中不可用的包,例如“mlxtend”包,您可以探索 Conda Forge。 Conda Forge 是一个社区驱动的存储库,托管由更广泛的 Conda 社区支持的库。通过在 Conda Forge 中搜索所需的包,您可以找到特定于该包的安装说明。

请记住,您还可以使用 Conda 包管理器更新包,使用诸如“conda update”之类的命令后跟包名,或者使用“pip”使用“pip install --upgrade”后跟包名。

通过遵循这些安装和包管理指南,您可以确保为本课程顺利、高效地设置 Python。

要从 Conda Forge 频道安装包,您可以使用以下命令:

conda install -c conda-forge <包名>

例如,要从 Conda Forge 安装 MLX Extent 包,您可以使用:

conda 安装-c conda-forge mlx_ext

此命令将在 Conda Forge 频道中搜索包并将其安装到您的环境中。

如果您需要的包在 Conda Forge 或任何其他 Conda 渠道中不可用,您也可以使用 pip 包管理器来安装它。 Pip 是 Python 的默认包管理器,允许您从 Python 包索引 (PyPI) 安装包。

要使用 pip 安装包,您可以使用以下命令:

pip install <包名>

例如,要使用 pip 安装名为“example-package”的包,您可以使用:

pip 安装示例包

确保将 <package-name> 替换为您要安装的包的实际名称。

请记住,在同时使用 Conda 和 pip 时,通常建议使用 Conda 作为主要包管理器以保持包兼容性和管理依赖项。但是,如果某个包在 Conda 中不可用,则使用 pip 是一个合适的选择。

使用 Conda 和 pip 安装 Python 和管理包的设置说明到此结束。请记住在您的计算机上安装任何东西之前观看视频教程,并按照建议的步骤进行操作以确保安装过程顺利进行。

 

3.3(可选)运行Python代码


3.3(可选)运行Python代码

在第三讲的第三个也是最后一个视频中,我将演示执行 Python 代码的不同方法。该视频将重点介绍 Jupiter 笔记本,这是一种文件格式和程序,可以在单个文档中方便地进行编码、文本编写、方程式绘制和绘图,这将用于即将到来的家庭作业。

在深入研究 Jupiter notebooks 之前,我将首先向您展示运行 Python 代码的最简单方法,即使用 Python 解释器或某些人称之为 REPL(Read-Eval-Print Loop)的东西。解释器允许交互式执行 Python 代码,这意味着立即评估代码。要使用解释器,您可以打开终端并输入“python”。从那里,您可以输入 Python 表达式并立即查看结果。例如,键入“print(1 + 2)”将显示结果“3”。您还可以将解释器用于更复杂的任务,例如循环遍历值并打印它们。

虽然解释器可用于快速计算或计算,但不建议用于编写更复杂的代码。很容易忘记计算,回滚并找到以前执行的命令会变得很麻烦。因此,对于更复杂的代码,最好使用 Python 脚本或 Jupiter notebook。

接下来,我将介绍另一种交互式 Python 解释器,称为 IPython。与常规解释器相比,IPython 提供了额外的特性和功能,包括语法着色、便于代码修改的历史功能和魔法命令。魔术命令是以百分号 (%) 开头并提供有用功能的特殊命令。一个这样的例子是“timeit”魔术命令,它允许对不同的代码实现进行基准测试。我通过实现两个用于反转字符串的函数并使用“timeit”命令比较它们的效率来证明这一点。

在展示了 IPython 的优势之后,我解释说 Jupiter 笔记本最初被称为 IPython 笔记本,因为它们是在 IPython 之上构建的。即使是现在,Jupiter notebooks 仍依赖 IPython,提供相同的优势和附加功能。要安装 IPython,我使用 Conda 并显示 IPython 网站以获取更多文档。

接下来,我将讨论第二种执行 Python 代码的方法,即使用 Python 脚本。此方法涉及创建一个扩展名为 .py 的文件,在该文件中写入代码,然后从命令行执行它。我提供了一个 Python 脚本示例,该脚本使用循环打印 0 到 4 之间的数字。

最后,我提到了遵守编码风格指南(例如 PEP 8)对于编写干净且可读的代码的重要性。我将展示如何在 Visual Studio Code 等集成开发环境中使用 Flake8 等 linter 来帮助识别和纠正样式问题,从而提高代码的整体质量。

该视频介绍了执行 Python 代码的不同方式,包括使用解释器、创建 Python 脚本以及利用 IPython 和 Jupiter 笔记本的优势。每种方法都有自己的优点,适用于不同的目的。

 

4.1 NumPy 简介(L04:Python 中的科学计算)



4.1 NumPy 简介(L04:Python 中的科学计算)

在本教程中,我们将介绍 NumPy 的基础知识,包括创建数组、访问元素、执行数组操作等。让我们开始!

首先,我们需要导入 NumPy 库。按照惯例,它是在别名 np 下导入的。运行以下代码导入 NumPy:

import numpy as np
现在我们已经导入了 NumPy,让我们创建我们的第一个数组。 NumPy 数组是使用 np.array() 函数创建的,该函数将 Python 列表作为输入。运行以下代码以创建数组:

arr = np.array([1, 2, 3, 4, 5])
print(arr)
您应该看到以下输出:

[1 2 3 4 5]
恭喜!您已经创建了您的第一个 NumPy 数组。现在让我们探讨一些我们可以对数组执行的基本操作。

访问数组元素

要访问 NumPy 数组中的元素,我们可以使用索引和切片,类似于 Python 列表。索引从 0 开始。

运行以下代码以访问数组中的元素:

 print (arr[ 0 ])   # Access the first element
print (arr[ 2 ])   # Access the third element
print (arr[- 1 ])   # Access the last element
输出将是:

1
3
5
我们还可以使用切片来访问数组中的一系列元素。切片的语法是start:stop:step,其中start是起始索引,stop是停止索引(不包括),step是步长。

运行以下代码对数组进行切片:

 print (arr[ 1 : 4 ])   # Access elements from index 1 to 3
print (arr[:: 2 ])   # Access every other element

输出将是:

[2 3 4]
[1 3 5]
数组操作

NumPy 数组支持各种数学运算,例如加法、减法、乘法和除法。这些操作按元素应用于数组。

运行以下代码进行数组操作:

arr1 = np. array ([ 1 , 2 , 3 ])
arr2 = np. array ([ 4 , 5 , 6 ])

# Addition
print (arr1 + arr2)

# Subtraction
print (arr1 - arr2)

# Multiplication
print (arr1 * arr2)

# Division
print (arr1 / arr2)
输出将是:

 [5 7 9]
[-3 -3 -3]
[4 10 18]
[0.25 0.4  0.5]
NumPy 还提供了可应用于数组的各种数学函数。例如,np.sin() 函数可用于计算数组的正弦值。

运行以下代码以将数学函数应用于数组:

arr = np. array ([ 0 , np.pi/ 2 , np.pi])

# Calculate sine
print (np.sin(arr))
输出将是:

[0.0000000e+00 1.0000000e+00 1.2246468e-16]

阵列形状和重塑

NumPy 数组的形状表示它的维度,例如行数和列数。我们可以使用 shape 属性来检查数组的形状。

运行以下代码来检查数组的形状:

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape)
输出将是:

(2, 3)
我们还可以使用 reshape() 函数更改数组的形状。这个函数允许我们调整数组的大小而不改变它的数据。

运行以下代码以重塑数组:

arr = np.array([1, 2, 3, 4, 5, 6])
reshaped_arr = arr.reshape((2, 3))
print(reshaped_arr)
输出将是:

[[1 2 3]
 [4 5 6]]
这些只是您可以使用 NumPy 执行的一些基本操作。该库提供了广泛的函数和功能来有效地处理数组。我鼓励您浏览 NumPy 文档以了解有关其功能的更多信息。
 

4.2 NumPy 数组构造和索引(L04:Python 中的科学计算)



4.2 NumPy 数组构造和索引(L04:Python 中的科学计算)

在第二个视频中,我想讨论非 Python 数组构造和索引。数组构造例程是用于创建数组的有用构建块或函数。当您需要一个稍后可以用特定值填充的占位符数组时,它们会派上用场。让我证明我的意思。

要创建一个由数字 1 填充的数组,我们可以使用 ones 函数。例如,ones((3, 3)) 将生成一个所有元素都设置为 1 的 3x3 数组。您还可以指定不同的维度,例如 ones((3, 4)),这将创建一个由 1 填充的 3x4 矩阵。 ones 函数接受各种参数,包括 dtype 参数,它确定数组的数据类型(64 位机器默认为 float64)。您可以将其设置为 int64 以创建一个整数数组。此外,您可以指定 order 参数,它控制数组在内存中的布局方式。默认是C,代表row-major style,但是你可以选择F fortran style layout。但是,对于此类,您无需担心这些细节,因为它们与将 NumPy 与 C 或 Fortran 代码结合起来更为相关。

同样,zeros 函数可用于创建一个用零填充的数组。您可以像使用它们一样使用它。请记住,如果您想了解有关这些功能的更多信息,可以使用 Jupyter Lab 或 IPython 中的帮助功能或使用问号 (?)。

还有一个空函数,它创建一个空数组而不初始化它的值。在大多数情况下,您不需要关心这个函数的细节,因为它只是创建一个具有任意值的数组。 identity 函数创建一个单位矩阵,其中对角线元素为 1,其余为 0。它可用于创建具有特定值的对角矩阵。

接下来是索引,NumPy 数组中的基本索引类似于 Python 列表中的索引。您可以使用方括号访问元素。例如,array[0] 返回第一个元素,array[1] 返回第二个元素,依此类推。切片也是可能的,就像 Python 列表一样。例如,array[1:4] 将返回从索引 1 到 3(不包括索引 4)的数组切片。

处理二维数组时,可以使用逗号表示法对二维进行索引。第一个索引指定行,而第二个索引指定列。例如,array[0, 0] 返回第一行第一列的元素,array[1, 2] 返回第二行第三列的元素,依此类推。

负索引可用于从数组末尾访问元素。例如,array[-1, -1] 将返回数组中的最后一个元素。同样,array[-1, -2] 将返回倒数第二个元素。这在处理大型数组时很有用,因为您不必跟踪数组长度。

要检索整行或整列,您可以省略其中一个索引。例如,array[0, :] 返回整个第一行,array[:, 1] 返回整个第二列。这相当于指定索引的范围(例如,第一行的 array[0, 0:3])。切片适用于两个维度,允许您选择数组的特定部分。例如,array[1:3, 2:4] 返回一个由第 1 行和第 2 行(不包括第 3 行)以及第 2 列和第 3 列(不包括第 4 列)组成的子数组。

布尔索引是 NumPy 的另一个强大功能。您可以使用布尔数组来索引数组,只选择与布尔数组中的 True 值对应的元素。例如,假设我们有一个名为 array 的数组,其形状为 (3, 3):

array( [[1, 2, 3] ,
       [4, 5, 6] ,
       [7, 8, 9] ])

我们可以根据条件创建一个布尔数组,比如array > 5,它会返回如下布尔数组:

array([[ False , False , False ],
       [ False , False , True ],
       [ True , True , True ]])
使用这个布尔数组作为原始数组的索引,我们可以只选择对应于 True 值的元素,结果是:

array([6, 7, 8, 9])
布尔索引允许根据特定条件灵活高效地选择元素。

除了基本索引之外,NumPy 还提供高级索引技术,例如整数数组索引和使用数组作为索引。这些技术支持对数组进行更复杂和非连续的索引操作。但是,它们是更高级的主题,对于基本数组操作可能不是必需的。

 

4.3 NumPy 数组数学和通用函数(L04:Python 中的科学计算)



4.3 NumPy 数组数学和通用函数(L04:Python 中的科学计算)

在投入大量时间创建比赛并为数组中的各个值建立索引之后,让我们继续讨论一个更有趣的话题:非付费数组、数学和通用函数。

通用函数,通常缩写为 Ufunk 或 Frank,是编程中一个强大的概念。通用函数 (Ufunk) 是通用函数的缩写形式,可以更高效、更方便地处理 Numpy 数组。它引入了一个称为矢量化的概念。

矢量化涉及对一系列对象(例如数组)执行数学或算术运算。向量化允许我们并行执行操作,而不是对数组的每个元素单独执行操作,利用元素之间缺乏依赖性。

例如,让我们考虑向数组中的每个元素添加一个数字的任务。使用 Python for 循环,我们将遍历每个元素并调用加法函数。然而,通过矢量化,我们可以同时对整个数组执行加法,而不需要循环。这显着提高了效率。

在 Numpy 中,矢量化是使用通用函数 (Ufunk) 实现的。在 Numpy 中实现了 60 多个 Ufunk,每个都有特定的用途。建议参考官方文档以获取可用 Ufunk 的完整列表。

为了说明这个概念,让我们关注逐元素加法,这是一种常见的操作。假设我们有一个二维数组,用 Python 实现为列表的列表。如果我们想给每个元素加 1,我们通常会使用嵌套循环或列表理解。然而,这些方法可能效率低下,尤其是对于大型阵列。

在 Numpy 中,我们可以使用 Ufunk“np.add”以向量化的方式将数字 1 添加到整个数组。这消除了对显式循环的需要并显着提高了性能。

值得一提的是,Numpy 利用运算符重载,允许直观地使用 Ufunk。例如,在数组和数字之间使用“+”运算符会自动调用“np.add”Ufunk。

另一个有用的 Ufunk 是“np.square”,它对数组中的每个元素进行平方。 Ufunk 函数可以是一元的(对单个值进行操作)或二元的(采用两个参数)。 Numpy 官方文档提供了有关可用 Ufunk 的更多详细信息。

转到一个更有趣的案例,让我们探索 Ufunk 与“reduce”方法的结合使用。 “减少”操作沿指定轴应用操作,将多个值减少为单个值。例如,我们可以使用“np.add”和“reduce”方法来计算列总和。

在这种情况下,我们滚动指定的轴(在本例中为轴 0)并使用指定的操作组合元素。 “reduce”操作通常与“map reduce”和 Hadoop 等概念相关联,其中计算分布在多个节点上,然后组合起来产生最终结果。

虽然这看起来势不可挡,但理解这些概念可以让您使用 Numpy 进行更高效和有效的编程。通过利用 Ufunk 和矢量化,我们可以轻松地对数组执行复杂的操作并优化我们的代码以提高性能。

请记住参考 Numpy 官方文档以获得可用 Ufunk 的完整列表,以及示例和使用指南。探索 Ufunk 的可能性将扩展您的工具包,并帮助您处理未来项目中的各种计算任务。

因此,在 NumPy 中,我们有一个称为 reduce 的函数,它允许我们沿数组的指定轴执行归约操作。缩减操作将多个值合并为一个值。默认情况下,缩减沿数组的第一个轴(轴 0)应用。

让我们举个例子来更好地理解这个概念。考虑以下数组:

array( [[1, 2, 3] ,
       [4, 5, 6] ,
       [7, 8, 9] ])
如果我们想计算列总和,我们可以使用 reduce 函数。此操作将翻转第一个轴(轴 0)并组合每列中的值。因此,结果将是一个包含每列总和的一维数组。

为此,我们可以使用 np.add 函数,该函数执行逐元素加法。我们将 np.add 作为函数参数传递给 reduce,表示我们想要沿指定轴添加值。

代码如下所示:

import numpy as np

array = np. array ([[ 1 , 2 , 3 ],
                  [ 4 , 5 , 6 ],
                  [ 7 , 8 , 9 ]])

column_sums = np.reduce(np.add, array )
print (column_sums)
输出将是:

[12 15 18]
在此示例中,reduce 函数遍历数组的列并将值加在一起。它将第一列 (1 + 4 + 7)、第二列 (2 + 5 + 8) 和第三列 (3 + 6 + 9) 组合成一个表示列总和的数组。

这种方法比手动遍历列并逐一添加值更有效。 NumPy 提供的矢量化操作允许我们利用优化的底层算法并行执行计算。

请记住,reduce 可以与 np.add 之外的各种其他函数一起使用,具体取决于您要执行的操作。减少的概念很强大,可以应用于许多不同的场景。

 

4.4 NumPy 广播(L04:Python 中的科学计算)



4.4 NumPy 广播(L04:Python 中的科学计算)

NumPy 提供了一个被称为“广播”的迷人功能,它引入了隐式维度,使我们能够执行在严格的线性代数范围内通常不可能执行的操作。这种广播的概念在使用数组时提供了更大的灵活性和便利性。

通过利用广播,NumPy 可以自动对齐具有不同形状的数组,本质上是扩展它们以匹配和执行逐元素操作。这种隐式维度创建使我们能够无缝地对不同大小的数组执行操作,从而产生简洁高效的代码。

在线性代数的上下文中,严格遵守数学规则来管理操作,广播提供了一个强大的工具来简化复杂的计算。它允许我们对具有不同形状的数组执行计算,无需手动重塑或遍历元素。

多亏了广播,我们可以毫不费力地对具有隐式维度的数组应用操作,获得可能需要大量手动操作才能获得的结果。此功能扩展了我们可以使用 NumPy 完成的范围,使其成为科学计算和数据分析的多功能且不可或缺的库。