杜克大学-Python-应用数据工程笔记-全-

杜克大学 Python 应用数据工程笔记(全)

001:认识你的联合讲师肯尼迪·贝赫曼 👨‍🏫

在本节课中,我们将认识本课程的联合讲师肯尼迪·贝赫曼,并了解他的专业背景与行业经验。

大家好,我是肯尼迪·贝赫曼,我将担任本课程的讲师。

我的背景是处理多个行业的数据解决方案,包括电影视觉特效、社交媒体初创公司和广告行业。

目前,我在金融服务行业从事基于云的大数据解决方案的架构设计与实施工作。

大数据生态系统中现在有许多有趣的产品,我希望这门课程能对你的数据之旅有所帮助。


本节课中我们一起认识了讲师肯尼迪·贝赫曼,了解了他跨越多行业的数据工程背景以及当前在金融领域专注于云大数据解决方案的工作。他的经验将为课程提供丰富的实践视角。

002:认识你的联合讲师诺哈·吉夫特 👨‍🏫

在本节课中,我们将了解本课程的联合讲师诺哈·吉夫特的背景与经验,这有助于我们理解课程设计的视角和目标。

我的名字是诺哈·吉夫特,我是本课程的讲师。

让我介绍一下我的背景。我最初在电影和电视行业工作,期间目睹了数次重大的技术变革,例如从模拟到数字的转变。那是一个巨大的变化,同时也涉及使用大数据系统。

因此,网络文件服务器、脚本编写、使用Python进行数据传输等技术,都为我职业生涯的下一阶段奠定了完美的基础。

之后,我来到湾区,在初创公司工作,并得以进行大规模的机器学习实践。

同时,我观察到,不同的工具确实引领我们达到了当前的阶段。

这个阶段的特点是,存在许多像Databricks、Snowflake这样的高级平台,人们正利用它们从组织的数据中真正获取解决方案。

本课程的设计目的,正是帮助你为构建此类解决方案做好准备。

构建能够展示你实际使用Databricks或Snowflake开发解决方案能力的作品集。本课程是你练习这些技能、并将职业生涯提升到新水平的绝佳机会。

我希望你能加入我们的学习之旅,我们很快将在课程中深入交流。


本节课中,我们一起了解了讲师诺哈·吉夫特从影视行业到数据工程与机器学习领域的跨界经历。他强调了利用现代数据平台(如DatabricksSnowflake)构建解决方案的重要性,这也正是本课程的核心目标——帮助你掌握相关技能,并打造证明自身能力的实践作品集。

003:大数据平台概述 🚀

在本节课中,我们将介绍Apache Hadoop,讨论MapReduce数据处理流程,并引入Spark及其核心概念。我们将探讨用于处理大数据问题的平台。

什么是大数据? 📊

“大数据”是一个被广泛使用的术语。定义它需要考虑我们处理的技术在不断变化。几十年前被认为是大数据的东西,现在可能在一部手机上就能处理。

因此,当我们思考大数据时,应该考虑那些数据量过大,无法在单台机器上存储或处理的情况。

针对此问题的解决方案主要围绕两个方面:

  • 分布式数据存储:数据存储在多个机器上。
  • 分布式数据处理:能够处理无法放入单台机器内存的数据。

市面上有许多大数据平台,有些更侧重于存储,有些更侧重于处理。

本课程将涉及的主要平台 🛠️

在本课程中,我们将关注以下几个主要平台:

以下是本课程将重点介绍的几个平台:

  1. Hadoop:它既是MapReduce算法的具体实现,也是一个包含分布式存储(如HDFS)和其他工具的大数据处理平台。
  2. Spark:这是一个当前非常流行的数据处理引擎,用于解决大数据问题。
  3. Snowflake:它最初是一个分布式存储解决方案,但正在演变为也包含数据处理解决方案。
  4. Databricks:它最初更侧重于处理,但也涉及存储。

总结 📝

本节课我们一起学习了大数据的基本概念,即数据量超出单机处理能力。我们介绍了解决此问题的两大支柱:分布式存储和分布式处理。最后,我们概述了本课程将要深入学习的四个主要大数据平台:Hadoop、Spark、Snowflake和Databricks。在接下来的章节中,我们将逐一探索它们的工作原理和应用。

004:Hadoop入门 🐘

在本节课中,我们将要学习Apache Hadoop的基本概念。Hadoop是一个用于处理大数据的平台,同时也是MapReduce编程模型的一种实现。我们将了解Hadoop如何工作,以及它在处理无法完全放入内存的大型数据集时所采用的策略。

什么是Apache Hadoop? 🤔

现在,我们来谈谈Apache Hadoop。Apache Hadoop是一个用于处理大数据的平台。它也是MapReduce编程模型的一种实现。

术语“Hadoop”既指MapReduce编程模型的Hadoop实现,也指Hadoop生态系统中的工具。Hadoop将工作分配到多台机器上,这些机器在集群中被称为节点。它将中间数据写入磁盘,以此作为处理无法全部放入内存的大型数据的策略。

Hadoop的工作流程 🔄

如果我们有存储在磁盘上的输入文件,并打算使用Hadoop来处理它们,第一步是将文件分割成多个分区。

然后,我们在这些分区上运行各种转换,这个阶段被称为Map阶段。在每次转换之间,中间文件会被写入磁盘。接着,下一个转换步骤从磁盘上的这些文件中读取数据。

最后,数据被合并以产生最终输出。这个最终的合并阶段被称为Reduce阶段

以下是Hadoop处理流程的核心步骤概述:

  1. 文件分割:将输入文件分割成多个分区。
  2. Map阶段:对每个分区应用转换操作,并将中间结果写入磁盘。
  3. Reduce阶段:读取磁盘上的中间结果,进行合并,生成最终输出。

这个过程可以用一个简化的公式来描述:
最终输出 = Reduce( Map( 分割(输入文件) ) )

总结 📝

本节课中我们一起学习了Apache Hadoop的基础知识。我们了解到Hadoop是一个分布式大数据处理平台,它通过将数据分割、在Map阶段进行转换、将中间结果写入磁盘,最后在Reduce阶段合并结果的方式来高效处理海量数据。理解这个工作流程是掌握后续更复杂数据工程概念的重要基础。

005:Spark入门 🚀

在本节课中,我们将学习Apache Spark的基本概念,了解它与Hadoop的区别,并掌握其核心架构和数据处理模型。


概述

Apache Spark是一个构建在Hadoop之上的大数据分析引擎或平台。它旨在将尽可能多的数据保存在内存中,这通常使其在处理速度上优于Hadoop,特别是在需要迭代计算(如运行机器学习算法)的场景中。与Hadoop不同,Spark自身不提供集群管理系统或分布式数据存储,而是能够与多种现有系统(如Hadoop YARN和HDFS)集成。


Spark与Hadoop的对比

上一节我们提到了大数据处理的基本背景,本节中我们来看看Spark与Hadoop的核心区别。

  • Hadoop:它是一个分布式计算和存储的框架。其核心是MapReduce计算模型和HDFS分布式文件系统。在数据处理过程中,Hadoop会将中间结果写入磁盘
  • Spark:它是一个分布式计算引擎,但依赖其他技术(如HDFS)来实现分布式存储。Spark的显著特点是将数据保存在内存中进行计算,这使得它对许多类型的问题处理速度更快。

Spark核心架构

理解了Spark的定位后,我们来深入其内部架构。以下是Spark运行时的几个关键组件:

  • Driver(驱动程序):这是Spark应用的主控程序,负责将用户代码解析、优化并分发给集群。
  • Executor(执行器):在集群的工作节点上运行的进程,负责执行Driver分配的具体计算任务,并将数据或状态返回给Driver。
  • Job(作业):一个由多个阶段(Stage)组成的完整计算任务,通常由用户的一个行动操作(Action)触发。
  • Stage(阶段):Job被划分成的更小的执行单元。阶段之间通常存在数据依赖(如Shuffle)。
  • Partition(分区)Task(任务):数据被切分成多个分区,每个分区会生成一个任务。任务在Executor上并行运行,以充分利用集群资源。

核心概念:弹性分布式数据集(RDD)

在Spark架构的核心,有一个名为弹性分布式数据集的基础抽象。它是Spark最初设计时用于支持机器学习等迭代算法的主要数据结构。

RDD(Resilient Distributed Dataset) 是一个不可变的、可分区的、并行操作的数据集合。它具有容错性,能够自动从节点故障中恢复。

其核心特性可以用以下伪代码概念来描述:

# RDD是一个抽象的逻辑数据集合,在物理上被分区存储在不同节点上
RDD = [Partition_1, Partition_2, ..., Partition_N]
# 对RDD的转换操作(如map、filter)会生成新的RDD,形成血缘关系(Lineage)
New_RDD = Old_RDD.map(function)
# 血缘关系记录了数据的衍生过程,用于在故障时重建丢失的分区,从而实现容错。

总结

本节课中我们一起学习了Apache Spark的基础知识。我们了解到Spark是一个基于内存计算的大数据分析引擎,通常比Hadoop MapReduce速度更快。它通过Driver和Executor的架构来协调任务,并将计算过程划分为Job、Stage和Task。其核心数据抽象RDD提供了容错的并行计算能力。记住,Spark专注于分布式计算,而将存储交由HDFS等外部系统负责,这是它与Hadoop一体化架构的主要区别。

006:弹性分布式数据集(RDD)简介

在本节课中,我们将介绍弹性分布式数据集,即RDD。我们将讨论使用RDD时的数据流,并向您展示如何创建和操作一个RDD。

概述

弹性分布式数据集是数据和任务在节点间分区的抽象。它有两种核心操作:一种是惰性的转换操作,另一种是返回计算结果的行动操作。RDD之所以具有弹性,是因为当节点发生故障时,它能够恢复并重新计算本应在该节点上处理的数据。

RDD的数据流

上一节我们介绍了RDD的基本概念,本节中我们来看看RDD在Spark作业中的具体数据流。

通常,一个作业会包含若干转换操作和一些行动操作。每个转换操作都会创建一个新的RDD,每个行动操作也会创建一个RDD。但需要注意的是,转换操作是惰性的,它们并不会立即应用到数据上,直到一个行动操作被触发执行。

以下是RDD数据流的典型过程:

  1. 从磁盘等数据源读取初始数据。
  2. 当我们对数据调用一个转换操作时,一个RDD被创建,数据在这个RDD内部被分区。分区由Spark自动完成,但您也可以手动调整。
  3. 经过一系列转换操作后,最终运行一个行动操作。
  4. 行动操作的运行会触发所有之前的转换操作真正应用到数据上,并最终完成计算,产生输出结果。

转换、行动与阶段

我们已经了解了转换和行动的区别。现在,让我们深入探讨一个影响性能的重要概念:洗牌操作

某些转换操作需要数据在分区之间重新分配,例如对数据进行重新排序。这类操作被称为洗牌操作,它们比其他操作的开销更大。在洗牌过程中,数据会被写入磁盘,这同时也成为了故障恢复的一个检查点。

洗牌操作还定义了阶段之间的边界。非洗牌操作会在一个阶段内连续执行,直到遇到一个洗牌操作,该洗牌操作即标志着一个阶段的结束和下一个阶段的开始。

总结

本节课中我们一起学习了弹性分布式数据集的核心概念。我们了解到RDD是Spark中一种弹性的、分布式的数据抽象,它通过惰性的转换和立即执行的行动两种操作来处理数据。我们还探讨了数据如何在RDD中流动,以及洗牌操作如何划分计算阶段并影响性能。理解这些基础概念是掌握Spark编程的关键。

007:弹性分布式数据集(RDD)演示 🚀

在本节课中,我们将学习如何在交互式PySpark环境中创建和操作弹性分布式数据集(RDD)。我们将通过一个简单的例子,演示RDD的创建、转换操作和行动操作,并理解其惰性计算特性。

启动PySpark交互式环境

首先,我们需要启动一个PySpark交互式环境。PySpark可以通过常规的Python工具(如Pip或Anaconda)安装。安装完成后,假设已安装适当版本的Java,我们可以在命令行中输入 pyspark 来启动PySpark shell。

启动后,shell会为我们提供一个Spark上下文(Spark Context)和一个Spark会话(Spark Session)。通常,在交互式shell之外编写Spark作业时,我们需要通过代码来设置上下文和/或会话。会话是与Spark交互的更现代方式,也是当前推荐的方式。然而,要查看RDD,上下文仍然是使用的工具。

创建简单的RDD

接下来,让我们创建一个简单的RDD。首先,我们创建一个数字列表。

numbers = list(range(15))

你可以看到我们有一个从0到14的数字列表。接下来,我们将使用这个列表作为输入来创建一个RDD。

rdd = sc.parallelize(numbers)

调用上下文上的 parallelize 方法,你可以看到返回的对象是一个RDD。

RDD的转换与行动操作

这个RDD有许多内置方法。这些方法包括代表转换(transformations)和行动(actions)的方法。转换操作是惰性的,而行动操作会触发实际计算。

以下是RDD的主要操作类型:

  • 转换(Transformations):对RDD进行变换,返回一个新的RDD,例如 mapfilter
  • 行动(Actions):触发计算并返回结果,例如 countcollect

现在,让我们在这个RDD上调用一个 map 方法。作为 map 方法的参数,我们将给它一个Lambda函数。这个函数的作用很简单,就是将每个值乘以2。

mapped_rdd = rdd.map(lambda x: x * 2)

接下来,我们使用 filter 转换操作。这里我们将使用一个Lambda函数,它会返回一个布尔值。这个Lambda函数将在 x 能被3整除时返回 True,否则返回 False

filtered_rdd = mapped_rdd.filter(lambda x: x % 3 == 0)

此时,你可以看到通过调用 count(这是一个行动操作),我们实际上触发了转换操作的发生,并且可以看到此时还剩下5个元素。

filtered_rdd.count()

总结

本节课中我们一起学习了RDD的核心概念和基本操作。我们了解到,RDD以分区(partitions)为单位处理数据。RDD有两种类型的操作:惰性的转换操作(transformations)和触发计算的行为操作(actions)。这些操作本身又被分组到不同的阶段(stages)中执行。通过实践,我们掌握了在PySpark shell中创建RDD、应用转换和行动操作的基本流程。

008:Spark SQL简介 🚀

在本节课中,我们将介绍Spark SQL模块。我们将了解数据集(Data Set)和数据框(Data Frame)的概念,并展示如何创建和操作PySpark数据框。

概述

虽然RDD(弹性分布式数据集)仍然是Spark运作的核心,但一个更现代的模块——Spark SQL——已被加入,并且现在通常是我们与Spark交互的主要方式。Spark SQL是一个用于结构化数据处理的模块。它利用数据结构信息和具体的计算逻辑来创建优化的操作。这些优化使其比直接使用RDD更快、更高效。

Spark SQL模块介绍

上一节我们概述了Spark SQL的作用,本节中我们来看看它的具体构成。Spark SQL提供了两种API:一种是SQL API,另一种是数据集(Data Set)API。在PySpark中,数据集以数据框(Data Frame)的形式呈现。在Scala版本中,数据集和数据框有所区分,而在Python版本中,只有数据框。但由于Python的交互特性,我们同样能享受到数据集的所有优势。

核心概念:数据集(Data Set)

一个Spark SQL数据集是一个分布式数据集合。它既拥有RDD的优势,又结合了经过优化的Spark SQL引擎。数据集API在Java和Scala中可用。

核心概念:数据框(Data Frame)

一个数据框是一个带有命名列的数据集。它创建了一种类似表格的结构,如果你熟悉Pandas等包中的数据框,可能会觉得这种结构很亲切,但两者有所不同。数据框是在PySpark中与数据交互的主要方式。

总结

本节课中我们一起学习了Spark SQL模块的基础知识。我们了解到Spark SQL通过优化操作提升了处理结构化数据的效率和速度。我们介绍了数据集作为分布式集合的概念,以及数据框作为带有列名的、表格化结构的数据集,并明确了数据框是PySpark中进行数据操作的主要接口。

009:PySpark DataFrame演示第一部分 🚀

在本节课中,我们将学习如何创建和初步探索PySpark DataFrame。我们将从创建一个Spark会话开始,然后通过读取CSV文件来创建DataFrame,并了解如何查看其结构和内容。

创建Spark会话

首先,由于我们不是在交互式shell中运行,所以需要创建一个Spark会话。以下是创建会话的步骤:

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName("PysparkExample").getOrCreate()

一旦会话创建完成,我们可以查看它。可以看到,它拥有我们之前指定的应用名称,版本是3.3,并且是一个内存中的Spark会话。

读取CSV文件创建DataFrame

接下来,让我们通过读取一个文件来创建一个DataFrame。我们将使用read.csv方法来读取一个CSV文件。

df = spark.read.csv("path/to/your/file.csv")

在创建的DataFrame中,列名被自动命名为_c0_c1_c2等。这是因为我们没有指示Spark读取文件中的标题行,而标题行通常会定义列名。

读取包含标题的CSV文件

现在,让我们再次读取同一个文件,但这次我们将使用option方法来告诉Spark读取标题行。

df_with_header = spark.read.option("header", "true").csv("path/to/your/file.csv")

现在可以看到,列名已经变成了account numberA BA BICOpenedbalance。这样,DataFrame的列名就与文件中的标题行对应起来了。

查看DataFrame的结构

为了更好地理解这个特定DataFrame的布局,我们可以使用printSchema方法来查看其结构。

df_with_header.printSchema()

这个方法会输出DataFrame的模式信息,包括列名、数据类型以及是否允许空值。通过查看模式,我们可以更清楚地了解数据的组织方式。

总结

在本节课中,我们一起学习了如何创建Spark会话,以及如何通过读取CSV文件来创建PySpark DataFrame。我们还了解了如何读取包含标题的文件,并查看DataFrame的结构。这些基本操作是进行数据工程和分析的重要第一步。

010:PySpark DataFrame演示第二部分

在本节课中,我们将继续学习PySpark DataFrame的操作,包括读取不同格式的文件、进行数据转换(如分组、聚合、添加列)、数据过滤以及多表连接。通过这些操作,我们将从多个数据源中提取并整合出有价值的信息。


上一节我们介绍了如何读取CSV文件并查看数据。本节中,我们来看看如何读取其他格式的文件并进行更复杂的数据处理。

现在,让我们读取另一个文件。可以看到,我们仍然使用 Spark.read 方法,并将 header 选项设置为 true。但这次我们读取的是一个Parquet文件,而不是CSV文件。Spark的读取功能支持多种不同的文件格式。

# 读取Parquet文件
df_parquet = spark.read.option("header", "true").parquet("path/to/file.parquet")

在DataFrame上,我们可以统计记录的数量。

# 统计记录数
record_count = df_parquet.count()

接下来,让我们对数据进行一些转换操作。

首先,我们将根据账户号码进行分组,并对结果进行求和。

# 按账户号码分组并求和
grouped_df = df_parquet.groupBy("account_number").sum()

然后,我们将账户信息和交易记录基于账户号码进行连接。

# 连接账户和交易数据
joined_df = accounts_df.join(grouped_df, "account_number")

这个操作会得到一个将账户号码与分组求和结果连接起来的新DataFrame。

以下是一个稍复杂的操作。我们为上面创建的求和DataFrame添加一个名为“New Balance”的新列。该列的值是初始余额与分组求和函数生成的名为“sum_amount”的列的总和。

# 添加新列
accounts_with_new_balance = joined_df.withColumn("New Balance", col("initial_balance") + col("sum_amount"))

打印当前账户DataFrame的结构,可以看到这里多了一个名为“New Balance”的新列。

# 打印结构
accounts_with_new_balance.printSchema()

现在,假设我们真正想从中获取的是那些账户透支(即余额为负)的账户信息。

我们将通过对DataFrame使用 filter 方法来实现。filter 方法需要一个能返回布尔值的条件。

# 过滤出余额为负的账户
negative_balance_df = accounts_with_new_balance.filter(col("New Balance") < 0)

我们的过滤条件是:选择“New Balance”列小于零的所有行。filter 方法会返回一个新的DataFrame,我们将其命名为 negative_balance


接下来,让我们读取另一种文件类型。这次我们将读取一个JSON文件。

JSON文件没有表头,因此我们无法像之前那样添加读取表头的选项。

# 读取JSON文件
clients_df = spark.read.json("path/to/file.json")

在这个文件中,数据包含账户号码、地址、电子邮件、名字和姓氏。


我们已经识别出那些余额为负的账户。现在,让我们将这些账户与对应的客户信息连接起来。

我们将把客户信息DataFrame与上面得到的负余额DataFrame进行连接,连接键是账户号码,并使用内连接,这样我们只会得到两个DataFrame中都匹配的行。

# 连接客户信息与负余额账户
result_df = clients_df.join(negative_balance_df, "account_number", "inner")

现在,我们已经识别出拥有负余额的客户,并将他们与具体的负余额信息关联了起来。


为了更清晰地查看结果,让我们在DataFrame上使用 select 函数来选择特定的列。我们通过传递一个列名列表来实现。

以下是需要选择的列:名字、姓氏、账户号码以及账户余额。

# 选择特定列
final_df = result_df.select(["first_name", "last_name", "account_number", "New Balance"])

这个操作会返回一个新的DataFrame。如果我们想查看结果,应该对这个返回的DataFrame使用 show 方法。

show 方法接受一个可选参数,用于指定要显示的行数。在这个例子中,我们只显示5行。

# 显示结果(前5行)
final_df.show(5)

因为 show 是一个触发计算的动作,所以现在它需要花费时间来执行所有必要的计算以得到最终结果。这就是为什么执行 show 操作比之前的转换操作耗时更长的原因。

我们可以看到,通过从三个不同的数据源开始,并使用连接、过滤和选择操作,我们现在得到了一个包含账户余额为负的客户信息的DataFrame。


总结

本节课中我们一起学习了PySpark DataFrame的核心操作。

  • Spark SQL 通常是使用Spark的主要接口,它在RDD之上引入了优化。
  • DataFrame 可以从多种文件类型(如CSV、Parquet、JSON)创建。
  • 通过使用 分组连接添加列过滤选择 等转换操作,DataFrame可以被灵活地处理和组合,以创建出满足特定分析需求的新DataFrame。

011:什么是Snowflake ❄️

在本节课中,我们将介绍Snowflake。我们将概述Snowflake的整体架构,包括其数据库存储层、计算层和云服务层。

Snowflake是一个为大数据设计的存储与计算平台。它以服务形式运行在公共云上,包括AWS、Microsoft Azure或Google Cloud。你可以根据偏好选择提供商。Snowflake使用其专有的Snowflake SQL,这意味着它并非采用其他数据产品设计的SQL版本。

大数据存储方法

在探讨大数据存储方法时,存在多种不同的实现方式。

以下是几种主要的大数据存储架构:

  • 共享一切架构:这是传统且最简单的方法。你将数据库安装在一台服务器上,所有希望在数据上运行的计算或进程都在这台与数据库相同的服务器上执行。大多数非大数据解决方案都采用这种方式。你会有一个关系数据库,它位于服务器上,你与之交互。这种方式很好,并且在数据量未达到影响效率的程度时,这无疑是最优选的解决方案。
  • 共享磁盘架构:在这种情况下,计算在多个独立的节点上进行,但这些节点都使用相同的存储。这种架构的缺点是,单个计算节点的计算效率可能会受到干扰,因为如果它们需要访问与另一个节点相同的数据,则可能需要等待。
  • 共享无架构:在这种情况下,每个计算节点都拥有自己专用的存储。

Snowflake采用了共享磁盘和共享无架构的组合,即一种混合方法。因此,其持久化数据存储在共享存储中,而每个处理节点在处理期间都拥有并使用其所处理数据子集的一个副本。这种设计允许非常快速且并发的处理,同时兼具共享持久化存储的简洁性。

总结

本节课我们一起学习了Snowflake的基本概念。我们了解到Snowflake是一个运行在主流云平台上的大数据存储与计算服务,它使用专有的SQL语言。我们还探讨了不同的大数据存储架构,并重点介绍了Snowflake所采用的、结合了共享磁盘和共享无架构优势的混合设计,这种设计旨在实现高效并发处理与存储管理简洁性的平衡。

012:Snowflake三层架构解析

在本节课中,我们将要学习Snowflake数据仓库的核心架构设计。Snowflake采用独特的三层分离架构,这种设计使其在性能、扩展性和成本管理方面具有显著优势。

架构总览

Snowflake被设计为三个独立的层次。最上层是云服务层,中间是计算层,最底层是数据库存储层。每一层都可以独立于其他层进行扩展。这意味着你只需为你实际使用的扩展部分付费。

数据库存储层

上一节我们介绍了架构总览,本节中我们来看看最底层的数据库存储层。

数据库存储层完全由Snowflake管理。文件的大小、加密类型、数据布局等所有细节都由Snowflake端管理,用户无法直接查看。数据以优化的列式格式存储,所有数据都经过压缩和加密。访问这些数据的唯一方式是通过计算层使用Snowflake SQL。

计算层

了解了数据如何存储后,本节我们来看看负责数据处理的计算层。

计算层中,你将主要与虚拟仓库进行交互。虚拟仓库是由Snowflake从云服务商处分配的一组节点集群。这些节点在不同的仓库之间是隔离的,因此一个仓库的性能不会影响另一个仓库。

这些仓库可以进行水平或垂直扩展。水平扩展是指向仓库添加额外的节点集群,而垂直扩展是指添加更大或更强大的节点。这两种扩展都可以在仓库运行时进行。

此外,这些仓库被设计为可以自动停止和自动恢复。这意味着你只需在仓库启动和运行时付费。

以下是两种主要的仓库类型:

  • 标准仓库:用于常规的数据处理任务。
  • Snowpark仓库:这是较新的类型,专为需要大量内存的任务设计,例如机器学习任务。

云服务层

最后,我们来看看协调一切的顶层——云服务层。

云服务层是你与所有其他层交互的接口层。它负责处理安全、身份验证和授权。同时,查询优化也发生在此层。你发送到Snowflake的每一个查询,在到达计算层之前,都会先经过云服务层的处理。

总结

本节课中我们一起学习了Snowflake的三层架构。我们了解到,其数据库存储层负责安全、高效地存储数据;计算层通过可独立扩展的虚拟仓库提供处理能力;而云服务层则作为大脑,协调安全、优化和所有交互。这种分层且独立扩展的设计,是Snowflake实现弹性、高性能和成本效益的关键。

013:Snowflake Web用户界面入门指南 🚀

在本节课中,我们将学习如何访问和使用Snowflake的Web用户界面。我们将从注册免费试用开始,逐步探索其核心功能,包括数据浏览、工作表编写以及查询执行。

概述

Snowflake是一个云数据平台,其Web界面是管理和操作数据的主要工具。本节将引导你熟悉该界面的布局和基本操作。

访问与注册

首先,访问Snowflake官方网站。你可以注册一个免费试用账户。建议你注册一个账户,并跟随本周课程中的示例进行操作。

当你首次登录Snowflake时,界面顶部会显示你的账户信息。

界面功能概览

Snowflake Web界面包含多个主要功能区域。以下是这些区域的简要介绍。

  • 工作表:这是你编写SQL代码并在Snowflake上运行的地方。
  • 仪表板:你可以在此处设置数据可视化仪表板。
  • 数据:这是访问数据服务层的地方,你可以在此管理数据库、模式和表。
  • 市场:提供第三方插件,Snowflake周围有一个庞大的生态系统提供这些服务。
  • 活动:你可以在此查看账户的历史活动记录。对于新账户,这里可能没有活动记录。
  • 管理:此部分包含账户和用户的管理设置。

浏览示例数据

现在,让我们查看Snowflake免费套餐附带的示例数据。在“数据”部分,有一个“数据库”区域。Snowflake会自动提供两个数据库,其中一个名为“示例数据”。

在我们的示例数据库中,可以看到多个模式。每个模式可以包含视图或表。例如,这个模式包含多个表。点击进入某个表,可以查看其详细信息,包括有权访问它的用户,以及该表包含的列。

要预览表中的数据,需要先选择一个仓库来运行预览查询。选择后,即可看到数据。

使用工作表编写查询

上一节我们浏览了现有数据,本节中我们来看看如何编写和执行查询。这主要通过“工作表”功能完成。

Snowflake提供了许多示例教程工作表,非常适合学习。你也可以创建自己的新工作表。

在工作表中,首先需要选择要操作的数据库和模式。虽然这不是强制要求(你可以在查询中显式指定),但在此处选择会更为方便。例如,选择 MOVIE 模式后,我们的查询就会默认针对该数据库和模式运行,无需在查询语句中重复指定。

工作界面还提供了自动补全功能。输入模式名后,可以看到该模式下的所有表。

假设我们想查看 CATALOG_SALES 表。同样,在Snowflake中运行任何操作都需要一个活跃的仓库。让我们选择系统自动提供的仓库。

然后,我们可以运行查询。结果区域会显示查询到的数据,以及查询本身的详细信息,例如执行耗时和表的元数据。

你可以通过这些工作表运行大量标准SQL语句,并为不同目的创建不同的工作表。此外,你还可以在此创建和删除表、修改权限,以及执行任何在标准SQL实现中预期的操作。

总结

本节课中,我们一起学习了Snowflake Web用户界面的基本使用方法。我们从注册和登录开始,了解了主要功能区域,并实践了如何浏览示例数据、在工作表中编写SQL查询以及执行查询查看结果。掌握这些基本操作是后续在Snowflake平台上进行数据工程工作的基础。

014:Snowflake平台管理指南 🏔️

在本节课中,我们将学习如何在Snowflake平台中进行基础的管理操作,包括用户与角色管理,以及计算仓库的创建与配置。这些是有效使用Snowflake进行数据工程工作的核心步骤。

用户与角色管理 👥

上一节我们介绍了课程概述,本节中我们来看看如何进行用户与角色的管理。这是控制数据访问权限的基础。

在Snowflake中,您可以进入“用户和角色”界面。这里可以查看当前账户中的所有用户和角色。

您登录时使用的账户即为账户所有者。如果需要,您可以在此处添加其他用户。

或者,您可以查看角色。角色是Snowflake权限管理的核心概念。以下是Snowflake默认提供的六个角色及其权限结构:

  • ACCOUNTADMIN:拥有所有权限。
  • SECURITYADMIN:拥有管理用户和角色的权限。
  • USERADMIN:拥有创建和管理用户与角色的权限。
  • SYSADMIN:拥有创建和管理仓库、数据库、模式等对象的权限。
  • PUBLIC:一个低权限角色,所有用户默认拥有。

这些角色之间存在继承关系。例如,ACCOUNTADMIN 角色继承自 SECURITYADMINSYSADMIN 的权限,从而拥有最高权限。

您也可以创建具有特定权限的新角色。例如,我们可以创建一个名为 API_ROLE 的角色,并将其继承自 USERADMIN。创建命令如下:

CREATE ROLE API_ROLE;
GRANT ROLE API_ROLE TO ROLE USERADMIN;

创建计算仓库 ⚙️

了解了权限管理后,接下来我们看看如何创建用于运行计算任务的计算仓库。

您可以为您的新仓库命名,并决定其规模。仓库规模决定了计算能力,也直接关联到信用点的消耗速度。因此,一个基本原则是:尽可能选择最小的可用规模

在创建时,您可以添加注释。通常,建议将仓库设置为“自动恢复”和“自动暂停”。这意味着:

  1. 当您向此仓库提交查询时,如果仓库未运行,它将自动启动。
  2. 查询完成后,经过一段设定的空闲时间,仓库会自动暂停。

请记住,您只需为仓库运行的时间支付信用点。因此,应避免仓库在空闲状态下持续运行。

您可以将自动暂停前的空闲时间设置为1分钟。甚至可以通过执行Snowflake SQL命令,将其设置为更短的时间。

在仓库类型上,您可以选择“标准”或“Snowpark优化型”。对于免费试用账户,通常只能选择“标准”类型。

创建完成后,您可以在界面中看到新的仓库。除了注册账户时自动设置的默认计算仓库外,您现在拥有了一个新的专用仓库。

您可能需要为不同的用户或不同的用途创建不同的仓库。例如:

  • 一个专门用于数据摄入的仓库。
  • 另一个专门用于为仪表板进行数据聚合计算的仓库。

这样可以更好地隔离工作负载和管理成本。

总结 📝

本节课中,我们一起学习了Snowflake平台的两项核心管理功能。首先,我们探讨了如何通过用户和角色来管理系统访问权限,并了解了默认的角色体系。其次,我们详细介绍了如何创建和配置计算仓库,重点强调了根据需求选择合适规模以及设置自动暂停以优化成本的重要性。合理运用这些管理功能,是构建高效、安全且经济的数据工程工作流的基础。

015:在Snowflake中创建表 🏗️

在本节课中,我们将学习如何在Snowflake控制台中创建数据库、模式和数据表,并理解如何通过角色和权限来管理对这些对象的访问。

概述

我们将首先登录Snowflake控制台,然后逐步创建一个新的数据库、一个新的模式,并在该模式中创建我们的第一个表。最后,我们将探讨权限管理,确保其他角色也能访问我们创建的资源。

创建数据库与模式

现在,我们回到了Snowflake控制台。在控制台的左上角,我们可以看到当前登录的用户名以及正在使用的角色。

我们可以将角色切换到用户有权访问的任何角色。由于当前用户是账户管理员,因此可以访问所有角色。但在常规设置中,用户通常仅限于某些特定角色。

在“数据”部分,我们已经可以看到现有的数据库。这些是Snowflake内置的示例数据库,其中也包含与Snowflake管理相关的数据。现在,我们可以创建自己的数据库。

选择我们创建的数据库后,可以看到可用的模式。我们可以创建一个新的模式。每个数据库都带有一些默认的模式。

创建数据表

现在,我们看到了三个模式,其中包括我们新建的模式。选择这个新创建的模式,可以看到其中还没有任何表。

我们可以开始创建表。界面会提供我们需要填写以创建表的SQL语句。创建表时,我们需要指定列名、列类型以及可选的注释。

在我们的表列表中,现在有了新表 demo1

权限管理

有一点需要注意:如果我们切换到具有不同权限的角色,将无法看到之前用管理员角色创建的这些模式和表。

切换回管理员角色,我们可以查看模式的详细信息,包括其权限。可以看到,此模式目前只对所有者(即账户管理员)拥有权限。

我们可以为特定角色添加权限。例如,为 DEVELOPER 角色添加权限。在权限选择界面中,有大量权限可供选择。对表也可以进行同样的权限设置。

在使用此界面选择权限时,请务必选中“授予”选项的复选框。如果我们希望其他角色也能使用该数据库,同样需要为其授予数据库本身的权限。

现在,如果我们切换回 DEVELOPER 角色并刷新页面,就可以看到之前创建的 schema 和新表了。

在Snowflake中创建表、模式和其他对象时,务必牢记:这些对象的所有者将拥有访问权限。如果有其他角色也需要访问,则必须明确授予它们相应的权限。

总结

本节课中,我们一起学习了在Snowflake控制台中创建数据库、模式和表的基本流程。关键步骤包括使用合适的SQL语句定义表结构,以及通过权限管理界面为不同角色授予必要的访问权限。理解所有权与权限授予是管理Snowflake数据对象的核心。

016:Snowflake仓库权限配置 🏭

在本节课中,我们将学习如何为Snowflake中的角色配置仓库(Warehouse)的使用权限,以便该角色能够在工作表中执行SQL查询。

上一节我们介绍了如何为角色分配数据库和模式的权限。本节中,我们来看看如何授予角色使用计算仓库的权限,这是执行查询的必要条件。

配置仓库使用权限

当我们在工作表中创建新的Notebook并尝试运行SQL时,需要关联一个负责执行查询的计算仓库。如果当前角色没有仓库的使用权限,则无法进行选择或执行操作。

以下是配置仓库权限的步骤:

  1. 在管理(Admin)区域,找到并进入“仓库”(Warehouses)部分。
  2. 这里会列出所有现有的仓库。点击你需要授权给角色的目标仓库。
  3. 在仓库详情页面,切换到“权限”(Privileges)标签页。
  4. 在此处,将使用该仓库的权限授予你的目标角色(例如 R_DEV 角色)。

核心概念:修改仓库的权限(如创建大型仓库)通常受到限制,因为如果资源使用不当,可能会产生高昂的费用。

在工作表中应用仓库

完成权限授予后,返回工作表界面。

以下是验证和应用仓库的步骤:

  1. 在工作表的仓库选择下拉菜单中,你现在应该能看到被授权的测试仓库(例如 TEST 仓库)已变为可用状态。
  2. 在此界面中选择该仓库,之后在此工作簿中运行的所有Snowflake SQL都将使用此仓库进行计算。
  3. 作为一种替代方法,你也可以在Notebook的开头使用SQL命令来设置仓库,这样就无需在图形界面中手动选择。例如:
    USE WAREHOUSE TEST;
    

设置查询上下文

为了方便查询,我们可以在工作表顶部预设默认的数据库和模式。

以下是设置方法:

  1. 在界面中选择你希望运行查询的数据库,例如 DEV 数据库。
  2. 接着选择相应的模式,例如 CDM 模式。
  3. 这意味着,在后续的查询中,我们无需在每条SQL语句中显式指定数据库和模式。当然,如果你需要跨数据库查询,仍然可以显式指定。

权限验证测试

现在,R_DEV 角色已拥有在 DEV 数据库的 CDM 模式中使用 TEST 仓库运行SQL语句的权限。

我们可以运行一个简单的查询进行验证:

SELECT * FROM SOME_TABLE;

由于该表可能没有数据,查询预期会返回零条结果。但重要的是,查询能够成功执行,这证明了访问权限已被正确授予。


本节课中我们一起学习了如何为Snowflake角色配置计算仓库的使用权限,并在工作表中进行应用和验证。掌握仓库的权限管理是控制计算资源成本和确保任务顺利执行的关键。

017:写入Snowflake 🗄️

在本节课中,我们将学习如何使用Python连接器(Snowflake Connector for Python)与Snowflake数据仓库进行交互。主要内容包括:设置连接环境、建立与Snowflake的连接、创建表以及将Pandas DataFrame中的数据写入Snowflake。

环境设置与包导入

首先,我们需要设置Python环境并安装必要的包。Snowflake连接器是一个Python包,可用于运行Snowflake SQL,并处理与Snowflake兼容的DataFrame。你可以用它来拉取、推送或操作数据。

以下是设置连接器环境的步骤。你应该查阅Snowflake官方文档,根据你特定的Python版本和环境进行设置。在本例中,我们只需使用pip安装特定版本的snowflake-connector-python。此外,为了在Jupyter Notebook中工作,我们还需要安装pandas、pyarrow、jupyter和jupyterlab。

# 安装命令示例
# pip install snowflake-connector-python==2.11 pandas pyarrow jupyter jupyterlab

现在,让我们在代码中导入必要的包。

import os
import snowflake.connector
from snowflake.connector.pandas_tools import write_pandas
import pandas as pd

我们导入了Python内置的操作系统模块ossnowflake.connector、用于写入pandas的write_pandas方法,并按照惯例将pandas导入为pd

配置连接参数与读取数据

在建立连接之前,我们需要设置一些变量,用于存储Snowflake的登录信息、密码以及我们将要使用的数据库、模式和表。

# 设置连接参数(在实际应用中,建议使用环境变量或配置文件管理敏感信息)
snowflake_user = ‘your_username‘
snowflake_password = ‘your_password‘
snowflake_account = ‘your_account‘
snowflake_database = ‘your_database‘
snowflake_schema = ‘your_schema‘
snowflake_table = ‘your_table‘
snowflake_role = ‘your_role‘
snowflake_warehouse = ‘your_warehouse‘

接下来,我们使用pandas的read_csv方法从一个CSV文件中读取一些示例数据,并查看其内容。

# 从CSV文件读取数据
df = pd.read_csv(‘path/to/your/accounts.csv‘)
# 查看数据前几行
print(df.head())

假设我们有一个账户表,包含账户号码、余额以及开户时间等字段。

建立Snowflake连接与创建表

要与Snowflake交互,首先需要建立连接。我们使用snowflake.connector.connect方法,并传入之前设置的参数,同时指定要使用的角色和仓库。

# 建立与Snowflake的连接
conn = snowflake.connector.connect(
    user=snowflake_user,
    password=snowflake_password,
    account=snowflake_account,
    role=snowflake_role,
    warehouse=snowflake_warehouse
)

# 创建游标以执行SQL语句
cursor = conn.cursor()

连接建立后,我们创建一个游标(cursor)来运行Snowflake SQL语句。现在,我们将在Snowflake中创建一个新表。

以下是创建表的SQL命令。我们创建一个名为dev_accounts的表,并指定列名和列的数据类型。

CREATE OR REPLACE TABLE dev_accounts (
    account_number INTEGER,
    customer_name STRING,
    balance FLOAT,
    opened_date DATE
)

在Python中,我们使用游标的execute方法来运行这段SQL代码。

# 执行SQL以创建表
create_table_sql = “““
CREATE OR REPLACE TABLE dev_accounts (
    account_number INTEGER,
    customer_name STRING,
    balance FLOAT,
    opened_date DATE
)
“““
cursor.execute(create_table_sql)
print(“Table created successfully.“)

将数据写入Snowflake

表创建好后,我们就可以将之前从CSV读取的Pandas DataFrame数据写入到Snowflake的表中。snowflake.connector.pandas_tools模块中的write_pandas函数可以高效地完成这个任务。

# 将DataFrame写入Snowflake表
success, nchunks, nrows, _ = write_pandas(
    conn=conn,
    df=df,
    table_name=‘DEV_ACCOUNTS‘, # Snowflake中表名通常大写
    schema=‘PUBLIC‘, # 替换为你的模式名
    database=‘YOUR_DATABASE‘ # 替换为你的数据库名
)

# 输出写入结果
if success:
    print(f“Data written successfully. Number of rows inserted: {nrows}“)
else:
    print(“Failed to write data.“)

write_pandas函数会返回一个元组,其中包含操作是否成功的标志、数据块数量、插入的行数等信息。

清理与关闭连接

所有操作完成后,务必关闭游标和连接,以释放资源。

# 关闭游标和连接
cursor.close()
conn.close()
print(“Connection closed.“)

总结

本节课中,我们一起学习了如何使用Python连接器与Snowflake进行数据交互。我们首先设置了环境并导入了必要的包,然后配置了连接参数并从本地文件读取了数据。接着,我们建立了与Snowflake的连接,创建了一个游标,并执行SQL语句在Snowflake中创建了新表。最后,我们利用write_pandas函数成功地将Pandas DataFrame中的数据写入到了Snowflake表中,并在操作完成后妥善地关闭了连接。掌握这些步骤,你就能使用Python高效地将数据导入Snowflake数据仓库了。

018:从Snowflake读取数据

在本节课中,我们将学习如何从Snowflake数据仓库中读取数据。我们将探讨使用SQL语句直接查询数据,以及如何将查询结果转换为Pandas DataFrame以便于进一步分析。

上一节我们介绍了如何将数据写入Snowflake。本节中我们来看看如何从Snowflake中读取数据。

使用SQL语句查询数据

我们可以使用游标对象执行SQL查询语句,从已创建的表中获取数据。

以下是执行查询并获取结果的步骤:

  1. 使用游标执行一个SQL SELECT语句,从accounts表中选择account_numberopened列,并限制返回10条记录。
  2. 调用fetchall()方法获取所有查询结果。
  3. 遍历并打印每条结果。
# 示例:使用游标执行SQL查询
sql_statement = "SELECT account_number, opened FROM accounts LIMIT 10"
cursor.execute(sql_statement)
results = cursor.fetchall()
for row in results:
    print(row)

通过这种方式,你可以与Snowflake中的表进行交互,执行SQL语句并通过游标获取结果。

将查询结果转换为Pandas DataFrame

除了直接获取结果,我们还可以将Snowflake表中的数据直接读入Pandas DataFrame,以便利用Pandas强大的数据分析功能。

以下是具体操作方法:

  1. 执行一个从目标表选择数据的SQL语句。
  2. 使用游标的fetch_pandas_all()方法,该方法会返回一个包含查询结果的DataFrame。
# 示例:将Snowflake查询结果读入DataFrame
df_from_snowflake = cursor.fetch_pandas_all()

关闭连接

完成所有数据操作后,为了释放资源,必须关闭游标和数据库连接。

# 关闭游标和连接
cursor.close()
connection.close()

本节课中我们一起学习了从Snowflake读取数据的两种主要方法:通过执行SQL语句并使用游标获取结果,以及利用fetch_pandas_all()方法直接将数据读入Pandas DataFrame。最后,我们强调了在操作完成后关闭连接的重要性。

019:访问Databricks

在本节课中,我们将学习如何在Azure环境中访问和使用Databricks服务。你将了解如何通过Azure门户的集成功能快速创建和管理Databricks资源,而无需进行独立的安装。


上一节我们介绍了数据工程平台的基本概念,本节中我们来看看如何在Azure中访问Databricks。

如果你在这里查看,我正位于我的Azure账户中。请注意,这里有一个Databricks集成选项。这个Databricks集成功能允许你非常快速地创建资源。从这里,你可以直接进行所需的所有构建和配置工作,而无需单独安装Databricks。

这是我们本课程中需要关注的主要集成方式。掌握这个方法就足以让你在本课程中取得成功。


本节课中我们一起学习了通过Azure门户访问Databricks服务的方法。我们了解到,利用Azure内置的Databricks集成,可以便捷地创建和管理相关资源,这简化了环境搭建的流程,是进行后续数据工程实践的关键一步。

020:在Databricks中使用Spark笔记本 📓

在本节课中,我们将要学习Spark笔记本在Databricks平台上的核心用途、功能以及具体操作方法。我们将从笔记本的通用概念讲起,逐步深入到Databricks环境中创建、修改、调度和开发Spark笔记本的实践步骤。


笔记本的用途与角色

要理解笔记本本身,我们首先需要深入探讨它们的用途以及它们所扮演的角色。

笔记本在数据科学项目中用于处理数据科学任务。它们也能帮助你进行可视化工作,例如绘制散点图。同时,笔记本也是团队协作的绝佳工具,例如,组织内的博士生与他们指导的学生可以共同进行一个研究项目。

但笔记本也具备工程侧重的功能。这可能意味着机器学习训练、机器学习部署、处理数据湖(例如大数据系统)、处理GPU使用、处理Docker格式的容器,以及云平台。因此,笔记本实际上是一种跨领域的方法。


笔记本的DevOps概念

另一个需要考虑的概念是“笔记本的DevOps”。在这种特定场景下,你可以使用一个Makefile来测试和部署代码,例如,将机器学习模型作为微服务的一部分部署到生产环境。可以有一个与你的Jupyter笔记本工作流相关联的Dockerfile,这将确保你能够精确复现项目中的内容。最后,可能还需要在requirements.txt中列出包依赖以及一些测试。你实际上也可以使用pytestnbval插件来测试笔记本。


Spark Databricks笔记本详解

现在,让我们深入探讨Spark Databricks笔记本的具体细节。

在Spark Databricks笔记本中,你可以执行多项操作,包括创建和修改笔记本、调度作业,以及基于这些笔记本开发代码。

以下是创建和修改笔记本的要点:

  • 你可以使用用户界面管理笔记本。
  • 你也可以使用命令行界面进行管理。
  • 你还可以调用工作区API。

通常,我会选择从头创建一个笔记本,或者导入、导出它,再或者将其附加到一个计算集群上。这些是笔记本的常见操作。

如果你想调度一个笔记本,过程相当直接。你可以在角落右键点击,看到“快速启动笔记本”选项,然后针对一个集群调度一个作业,例如,为你的组织生成每周报告。

一旦你调度了作业,它就会重复运行,甚至会在作业开始、成功或失败时向你发送电子邮件提醒。


使用笔记本进行开发

在使用笔记本进行开发时,需要记住以下几点:

  • 这些笔记本专为开发和运行代码单元而设计。
  • 你可以混合搭配使用不同的语言,例如Python、R、Scala和SQL。
  • 你可以操作这些代码单元,并在Markdown中包含文档说明。

实践练习:调度Spark笔记本

包含笔记本练习总是结束本教程的好方法。因此,我将演示如何调度一个Spark笔记本。

为此,我将进入我的Databricks界面,并确保我们有一个正在运行的计算集群。

你可以看到我有几个不同的集群:一个单节点集群和一个拥有12个核心的集群。如果我转到我的工作区,我可以查看我之前使用的这个快速启动笔记本,并确保它已附加到一个集群。

如果我想将这个快速启动笔记本与一个调度作业关联起来,我只需在这里选择“调度”,然后将其命名为一个调度作业。例如,这可以设置为每天上午9点运行。我会在这里设置,并选择仅在运行此作业出现问题时向我发送消息。让我们创建它。

好了。现在,这个快速启动作业将在每天上午9点运行。我也可以立即运行它。如果你要创建一个调度作业,首先手动运行一次通常是个好主意。我们现在可以运行它。它将检查我们作业的逻辑。

因此,调度作业已设置完成。这是使用Databricks笔记本时更有用的一个方面。


总结

本节课中,我们一起学习了Spark笔记本在Databricks平台上的核心功能。我们了解了笔记本在数据科学和工程领域的双重角色,探讨了与之相关的DevOps概念。接着,我们详细介绍了在Databricks中创建、修改、调度笔记本以及使用多语言进行开发的具体方法。最后,通过一个实践练习,我们演示了如何为笔记本创建定时调度作业。掌握这些技能,将帮助你更高效地在Databricks环境中进行数据工程和数据分析工作。

021:在Databricks中使用数据

概述

在本节课中,我们将学习如何在Databricks Spark环境中使用数据。我们将涵盖从上传数据到文件系统、访问内置数据集、集成Azure开放数据集,到探索Databricks文件系统(DBFS)以及了解其支持的数据源和ETL流程。

开始使用数据

要开始在Databricks Spark中使用数据,首先需要进入一个目录。在这个位置,你可以看到我已经将数据上传到了DBFS(Databricks文件系统),这是一个CSV文件。上传完成后,我就可以使用笔记本(Notebook)甚至命令行工具来操作它。

接下来,当文件上传完成时,系统会提供一个访问路径。你可以看到,从PySpark、Pandas、R、Scala等任何语言中,都有示例代码展示如何将该数据加载为数据框(DataFrame)。

当我在笔记本中加载这个数据框后,可以看到数据已成功载入。如果我执行display操作,就能直接在Spark笔记本中看到输出结果。

关于Databricks数据集

上一节我们介绍了如何上传和使用自己的数据,本节中我们来看看Databricks自身提供的数据集。

使用数据科学的一种方式是根本无需上传数据,而是直接从Databricks数据集的路径访问到你的笔记本中。这是一个测试不同工作流和展示这些内部数据的绝佳方式。你甚至可以查看数据的大小。在笔记本中查询这些数据非常简单,只需使用display(dbutils.fs.ls(...))这个概念。

Azure开放数据集

现在,让我们谈谈Azure开放数据集。这也是一个非常独特的服务。

它是Azure Databricks集成中非常强大的一部分。要使用它,你只需要安装azureml-opendatasets库。安装完成后,你可以将该库应用到所有笔记本中。安装后,你就可以导入数据了。例如,我们可以导入NOAA天气数据,设定一个日期范围(比如从2019年到3月),然后直接使用结果。这是一种非常强大的方式,只需几行代码就能获取新数据集并进行操作。

Databricks文件系统(DBFS)

那么,Databricks文件系统本身呢?如何更深入地探索它?正如之前提到的,一个简单的方法就是使用display操作。

这里我们使用dbutils.fs.ls命令,并指向Databricks数据集目录。这是一种信息量很大的方式来查看当前情况。你也可以将其理解为使用目录和文件语义的对象存储。

它将你的数据保存到一个对象存储位置。另一个非常强大的功能是直接浏览和上传数据的概念,正如我早先提到的。需要指出的是,你必须在管理员设置中启用此功能。

如果我们在这里使用Databricks文件系统,以下是一个如何与其交互的好例子:你可以使用%fs lsdbutils.fs.ls、带:sls命令本身,或者dbfs ls(这将是本地文件系统)。实际上,这取决于你是在本地使用还是在集群本身上使用。这里的关键要点是,集群有能力进行分布式磁盘操作。

这里有一个使用DBFS命令的好例子,它显示了数据实际存储的位置。如果你想从根位置读取数据,这里有一个使用%fs的例子。如果你想增加与DBFS通信的能力,你也可以在这里添加路径。

数据源

关于数据源,需要注意以下几点:默认支持的数据源包括Avro、二进制文件、CSV、Hive表、图像、JSON、LibSVM、压缩文件、MLflow实验、Parquet、XML、ZIP文件等。因此,有大量的默认数据集和数据源。

此外,还有额外的数据源,包括Azure、MongoDB、Redis或Snowflake等。这意味着与第三方数据源也有深度集成。

Databricks ETL流程

在Databricks ETL方面,需要指出的一点是,它能够处理日志文件和媒体,将其移动到存储中,使用Azure Databricks Spark进行预处理,然后输出一个模型。这实际上就是Databricks的ETL(提取、转换、加载)管道概念。通过Azure集成,你可以相当简单地完成这个过程。

总结

本节课中,我们一起学习了在Databricks环境中使用数据的多种方式。我们从上传文件到DBFS开始,学习了如何加载和显示数据。接着,我们探索了直接使用Databricks内置数据集和强大的Azure开放数据集的方法。然后,我们深入了解了Databricks文件系统(DBFS)的操作命令和其作为对象存储的本质。我们还列举了Databricks支持的各种默认和第三方数据源。最后,我们简要了解了Databricks如何作为ETL管道,从数据提取、转换到加载和建模的完整流程。掌握这些方法,将帮助你在Databricks平台上高效地进行数据工程任务。

022:在Databricks中管理工作空间 🧱

在本节课中,我们将要学习Databricks平台的核心概念之一——工作空间。工作空间是您与团队成员协作、组织项目资产(如笔记本和库)以及管理代码版本的中心区域。我们将详细介绍如何创建和管理工作空间,并探索其协作与版本控制功能。

工作空间简介

工作空间是Databricks平台上的一个位置,您可以在其中执行多种操作,以帮助您与其他用户协作并组织项目。

首先,当您查看工作空间时,需要注意的一点是,您可以在左上角创建新用户。这些新用户随后便能在您的工作空间内工作。

您还可以执行其他操作,例如将其视为一个包含笔记本、库、电子邮件流、实验等资产的沙箱。这里展示了一个如何创建新笔记本、新库文件夹或执行任何所需操作的示例。此外,您可以导入其他笔记本,例如来自Databricks的文档。

创建工作空间与资产

现在,让我们具体看看如何操作。

如果我转到我的Azure账户,深入“计算”部分,然后进入工作空间,我就可以在这里进行操作。我只需右键单击,即可创建新笔记本、新库、新文件夹或执行任何所需操作。

接下来,让我们创建一个笔记本。我们将其命名为“hello”。此时,我需要选择默认语言。假设我们使用Python。创建该笔记本后,它将位于我的工作空间中,并且我可以与其他用户共享它。

团队协作功能

工作空间的另一个核心理念是支持团队协作。对于大数据项目而言,这至关重要。在基于团队的环境中,您希望让许多不同的人员(例如数据科学团队、数据工程师、机器学习工程师)一起工作。请注意,一旦您拥有了一个工作空间,就可以开始执行诸如与集群协作、摄取数据、邀请人员加入您的团队等操作。因此,它确实是协作工作流程的起点。

如果您想邀请某人加入您的团队,只需右键单击,将他们添加到您的团队中。然后,他们也可以成为您Azure Databricks工作空间的一部分。

版本控制与代码仓库

代码仓库是另一个令人兴奋的组件,因为它可以让您的代码处于版本控制之下。这样做的好处是,您可以实际执行持续集成,或为项目维护行业标准的软件工程实践所需的一切操作。它不仅与GitHub配合使用,还能与Bitbucket Cloud、GitLab、Azure DevOps、AWS CodeCommit等平台紧密集成。您可以看到,添加一个仓库并连接到远程Git仓库是相当简单的。一旦完成,您就可以将文件在仓库和工作空间之间来回移动。

工作空间与仓库的交互

关于仓库的一些关键事实是:您可以将文件从工作空间移动到仓库。这是一种最佳实践,您可以将工作空间视为沙箱,将文件移到仓库后,再将其签入。这样,您的笔记本就能处于版本控制之下。因此,使用仓库可以完成许多出色的工作。

总结

本节课中,我们一起学习了Databricks工作空间的管理。我们了解了工作空间作为协作和项目组织中心的基本功能,包括如何创建用户、管理笔记本等资产。我们探讨了工作空间在促进数据科学团队、工程师等多角色协作中的关键作用。最后,我们介绍了代码仓库如何与工作空间集成,以实现版本控制和行业标准的开发实践,从而确保项目的可维护性和团队的高效协作。

023:Databricks高级功能

在本节课中,我们将探讨Databricks平台的几个高级功能。这些功能旨在帮助数据工程师和科学家更高效地管理数据、构建特征和进行机器学习建模。


特征存储

上一节我们介绍了Databricks的基础功能,本节中我们来看看特征存储。特征存储用于管理和追踪用于机器学习模型的复杂特征工程过程。它支持特征溯源,帮助用户了解特征的来源,并促进不同团队对相同特征的协作开发。此外,特征存储还能与模型评分和服务集成,确保在生产环境中清晰掌握每个特征的实际作用和影响力。

图框架

除了特征存储,Databricks还提供了图框架功能。图框架是机器学习的另一种建模方式。图模型与传统表格模型不同,它使用不同的描述性统计方法。

以下是图分析中常见的几种统计概念:

  • 中心性:用于识别网络中最重要的节点。
  • 社群发现:用于找出网络中紧密连接的群体或集群。
  • 影响力分析:在社交网络等场景中,识别那些拥有大量互动和连接的影响者。

基于这些网络关系,可以训练专门的预测模型。

Delta Lake

另一个核心高级功能是Delta Lake。Delta Lake提供了一个可扩展的元数据层,并统一了流处理和批处理的接口。同时,它支持ACID事务。

ACID 是原子性、一致性、隔离性、持久性的缩写,这意味着在Delta Lake上执行的事务是可重复且可扩展的。

此外,Delta Lake现已开源,这为社区开发和采用带来了更多可能性。


总结

本节课中我们一起学习了Databricks平台的三个关键高级功能:特征存储用于管理机器学习特征的生命周期;图框架为基于关系的建模提供了强大工具;Delta Lake则通过ACID事务和统一的处理接口,构建了可靠的数据湖基础。这些功能共同增强了Databricks在复杂数据工程与机器学习工作流中的能力。

024:Databricks上的PySpark简介 🚀

在本节课中,我们将要学习PySpark的基础知识,特别是如何在Databricks平台上使用它来处理大规模数据。我们将了解DataFrame的核心概念,并探索如何通过熟悉的Pandas API来操作PySpark,从而实现代码的平滑迁移和高效的大数据处理。

核心概念:DataFrame与API

DataFrame是一种列式数据结构,类似于CSV文件或Excel电子表格。您可以通过常规的Pandas API或Koalas接口与这些DataFrame进行交互。Koalas接口能够与Spark语言通信,并大规模地处理DataFrame。

以下是一个关键的工作流程示例:数据湖(对象存储)中的数据通过DBFS或集群被合并处理,随后进行大规模的数据操作。这可以是一个应用函数,我们接收输入,执行计算,将计算应用到DataFrame的所有行,最后可能进行可视化。

PySpark DataFrame 操作示例

上一节我们介绍了DataFrame的基本概念,本节中我们来看看具体的代码操作。

以下代码展示了如何创建PySpark DataFrame并进行基本操作:

from pyspark.sql import Row

# 创建部门行
department = Row("id", "name")
# 创建员工行
employee = Row("first_name", "last_name", "email", "department_id")

这段代码直接源自Azure Databricks的文档,其工作方式与常规编程非常相似,区别在于它能够处理大数据。

数据合并与用户定义函数

以下是两个关键操作的介绍。

合并DataFrame
合并两个DataFrame非常简单。可以使用union方法。

union_df = df1.union(df2)
display(union_df)

创建用户定义函数
构建UDF也很直接。首先定义一个函数,然后将其注册以便应用到DataFrame上。这正是其强大之处——能够大规模地应用这些函数。

from pyspark.sql.functions import udf
from pyspark.sql.types import IntegerType

def square(x):
    return x * x

square_udf = udf(square, IntegerType())
# 随后可将 square_udf 应用于DataFrame列

PySpark Pandas API:解决扩展性问题

常规Pandas API的一个局限是难以扩展至大数据场景。它更适用于学术规模的数据集。在现实场景中,您需要能与更大数据平台交互的工具。

PySpark Pandas API解决了这个问题。只要在Databricks Runtime 10.0或更高版本上运行,您就可以使用它。

import pyspark.pandas as ps

它的优势在于,其使用方式与您熟悉的Pandas非常相似,但幕后却在分布式处理数据,从而能够随数据规模扩展。

实践对比:Pandas vs PySpark Pandas

让我们通过实际操作来感受两者的区别。以下代码对比了常规Pandas和PySpark Pandas的使用。

首先导入必要的库并创建序列:

import numpy as np
import pandas as pd
import pyspark.pandas as ps

# 创建Pandas Series
p_series = pd.Series([1, 2, 3, 4, 5])
# 创建PySpark Pandas Series
ps_series = ps.Series([1, 2, 3, 4, 5])

运行后,两者操作方式相似。使用ps_series可以查看输出。

创建与排序DataFrame

# 创建Pandas DataFrame
pdf = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
# 创建PySpark Pandas DataFrame
psdf = ps.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})

# 排序
pdf_sorted = pdf.sort_values(by='a')
psdf_sorted = psdf.sort_values(by='a')

两者工作流几乎完全相同,唯一的本质区别是后者能处理大数据。

查看数据与统计
您可以使用熟悉的Pandas方法,如.head()查看前几行,或.describe()获取描述性统计信息。

# 查看前几行
print(psdf.head())
# 获取描述性统计
print(psdf.describe())

即使面对海量数据,由于PySpark Pandas的封装,操作方式与处理小数据集一致。

数据选择与切片
选择列、使用loc进行标签索引或切片等操作也与Pandas类似。

# 选择单列
col_a = psdf['a']
# 选择多列
cols_ab = psdf[['a', 'b']]
# 使用loc切片
slice_data = psdf.loc[0:2, 'a']

应用自定义函数

在数据工程工作流中,一个经典且强大的操作是编写函数并将其应用到DataFrame上。

您可以直接应用函数,也可以使用Lambda表达式。

# 定义一个平方函数
def square(x):
    return x ** 2

# 将函数应用到DataFrame的列上
psdf['a_squared'] = psdf['a'].apply(square)

# 使用Lambda表达式
psdf['b_squared'] = psdf['b'].apply(lambda x: x ** 2)

这为熟悉Pandas的程序员提供了强大且熟悉的方式来利用PySpark处理大数据。

总结

本节课中我们一起学习了PySpark在Databricks上的核心应用。我们理解了DataFrame作为列式数据结构的基础,探索了通过PySpark Pandas API如何用类似Pandas的语法处理大规模数据,并实践了数据操作、合并、自定义函数应用等关键技能。关键在于,PySpark使得为小数据编写的Pandas代码能够无缝扩展到大数据环境中,极大地提升了数据工程的处理能力和效率。

025:探索Databricks Azure功能

在本节课中,我们将要学习如何在Azure云计算平台上探索和使用Databricks平台的核心功能。我们将了解不同的工作模式、关键组件以及如何开始使用各项服务。

工作模式切换

首先,我们来看看Databricks平台与Azure云计算平台的集成界面。请注意,在界面的最上方,你可以在两种模式之间进行切换。

这是一个非常重要的考量点。数据科学与工程模式主要用于进行Notebook开发,其工作流程针对此类任务进行了优化。如果你选择此工作流程,从资源到搜索、数据再到计算的所有设置,都是为了让你能够快速启动计算资源并处理不一定与机器学习直接相关的任务。因此,默认的集群启动配置中不一定包含GPU。

如果你切换到机器学习模式,界面和功能会有所变化。你会注意到,系统会引导你使用其他类型的功能,包括AutoML、模型训练,以及查看特征存储等。所以,了解这两种不同的模式非常重要。

核心创建功能

现在,如果你想探索这里的一些功能,让我们开始深入了解。首先,你拥有“创建”这一核心概念。以下是你可以创建的主要资源类型:

  • Notebook:用于编写和运行代码。
  • Table:用于管理数据表。
  • Cluster:用于创建计算集群。
  • Job:用于安排和运行作业。
  • Repo:用于与GitHub集成。
  • AutoML Experiment:用于启动自动机器学习实验。
  • Experiment:用于管理机器学习实验。
  • Model:用于注册和管理模型。

根据你想要完成的任务,这里是很好的起点。

工作区与数据管理

正如我们之前讨论过的,工作区是你实际存放Notebook的地方。Repo则是你与GitHub进行代码版本控制集成的地方。

接下来,如果你向下滚动到数据部分,这里是你将数据上传到DBFS(Databricks文件系统)的地方。你也可以查询已集成的现有数据表。例如,对于这里的“diamonds”表,我可以查看其模式样本数据,并对其执行一些操作。

需要注意的是,执行这些数据操作需要关联一个计算集群,以便系统能够查询数据并进行描述性统计分析。

计算集群配置

如果你想配置计算实例,这里有几个要点需要指出。如果我进入“计算”部分并选择“创建集群”,有一个需要注意的地方可能会让人感到意外:当你选择Databricks运行时版本时,需要了解有标准模式ML模式之分。

如果你选择标准模式,一些机器学习库可能没有预装。如果你尝试运行一个示例Notebook,它们可能无法工作。如果你选择ML模式,请注意软件版本实际上略有不同。在许多情况下,你希望选择最新的ML版本(可能从非GPU版本开始以控制成本),然后在这里设置你的集群。

其他功能模块

最后,还有一些其他需要注意的功能。你可以访问工作流选项卡、实验选项卡、特征存储选项卡,甚至这里的模型选项卡,来查看已加载的不同模型。

当你进入并查看这里的模型时,你还可以深入查看详细信息,了解其状态,查看它是否已被部署到生产环境,甚至使用模型进行推理预测

课程总结

本节课中,我们一起学习了如何在Azure Databricks平台上导航。我们了解了数据科学/工程模式与机器学习模式的区别,探索了创建各种资源(如Notebook、集群和作业)的入口,并熟悉了工作区、数据管理、计算集群配置以及其他高级功能(如工作流、实验和模型管理)的基本操作。掌握这些界面和功能是有效利用Databricks进行数据工程和机器学习项目的基础。

026:从DBFS到AutoML工作流

在本节课中,我们将学习如何将存储在Databricks文件系统(DBFS)中的数据,通过AutoML功能,快速构建一个高级的机器学习工作流。整个过程旨在让初学者也能轻松上手。

概述:从数据到模型

首先,我们需要理解起点和终点。我们的起点是存储在DBFS中的数据表。我们的终点是创建一个可以预测特定目标的机器学习模型。本节将演示如何利用Databricks的界面化工具,无需编写复杂代码,即可完成这一过程。

探索DBFS中的数据

上一节我们介绍了DBFS作为数据存储的位置。本节中,我们来看看如何探索其中的数据,并确定可用于机器学习模型的特征。

Databricks的数据探索工具能直观地展示数据。例如,打开“diamonds”表,工具会显示数据表的schema(结构)并提供数据样本。这有助于我们了解潜在的特征,如caratcutcolor等。

# 示例:数据表可能包含的列
columns = ['carat', 'cut', 'color', 'clarity', 'depth', 'table', 'price', 'x', 'y', 'z']

同样,如果我们查看“people”表,可以看到其中包含idfirst_namemiddle_namelast_namegender等列。基于这些数据,我们可以构建一个预测性别(gender)的分类模型。

配置AutoML实验

在了解了数据之后,下一步是配置一个AutoML实验来自动化模型构建过程。

首先,在Databricks界面中转到“Experiments”部分。创建一个新的AutoML实验时,需要进行几项关键配置:

以下是配置AutoML实验的主要步骤:

  1. 选择计算集群:选择一个已设置好的集群。例如,一个拥有12个核心、运行DBR 11.0版本的集群。
  2. 选择问题类型:由于我们的目标是预测性别,这是一个分类问题,因此选择“Classification”。
  3. 指定数据位置:从数据目录中选择我们想要使用的数据集,本例中选择“people”数据库。系统会自动读取其schema并处理数据插补等问题。
  4. 设置预测目标:在下拉菜单中选择我们想要预测的列,即“gender”。

完成这些设置后,系统会为我们创建一个实验。点击开始,AutoML便会自动进行数据预处理、模型训练和超参数调优。

分析与部署模型

实验运行完成后,我们可以查看所有训练运行的结果。系统会列出每次实验的详细信息。

例如,在实验历史中,可以看到每次运行的时间、使用的模型类型(如scikit-learn模型)、执行用户以及源代码笔记本。模型追踪系统在此发挥着重要作用。

# 示例:模型追踪可能记录的信息
run_info = {
    'experiment_id': '123',
    'run_time': '2.5 minutes',
    'model_type': 'sklearn.ensemble.RandomForestClassifier',
    'accuracy': 0.95
}

如果对某个模型结果满意,可以直接将其选中并部署到生产环境。此外,Databricks还会自动生成两个非常有用的笔记本:

  • 最佳模型查看笔记本:展示如何部署该最佳模型。
  • 最佳模型数据探索笔记本:展示用于该模型的探索性数据分析代码。

这意味着,即使你后续打算完全自己编写代码,这个AutoML工作流也为你提供了绝佳的起点和参考。

总结:高效的工作流起点

本节课中,我们一起学习了如何在Databricks上构建一个从数据到模型的快速工作流。我们首先探索了DBFS中的数据表,然后通过配置AutoML实验自动构建了一个分类模型,最后分析了实验结果并了解了如何部署模型。

这个工作流的核心价值在于其简洁性:无论是将数据上传到DBFS,还是直接使用已有的数据,你都可以通过AutoML快速获得一个初步的、可投入生产的模型方案,作为你Databricks项目一个高效的开端。

027:加载、注册和部署机器学习模型 🚀

在本节课中,我们将学习如何在Databricks平台上,对机器学习模型进行加载、注册和部署。我们将通过具体的API命令和用户界面操作,了解如何从本地或远程获取模型,并最终将其部署为可调用的服务。


上一节我们介绍了Databricks平台的基本概念,本节中我们来看看其核心功能之一:机器学习模型的管理与部署流程。

Databricks平台的一个强大特性是机器学习模型的记录(Logging)加载(Loading)注册(Registering)部署(Deploying)。让我们通过几个例子来具体了解这个过程。

首先,我们可以使用API命令来操作模型。例如,以下代码展示了如何使用Python从本地加载一个模型:

# 示例:使用Python加载本地模型
import mlflow
model = mlflow.pyfunc.load_model('path/to/local/model')

当然,模型也可以从一个Spark DataFrame中加载。除了使用代码,我们还可以通过Databricks的用户界面(UI)来交互式地管理模型。


接下来,让我们通过用户界面来查看一个具体的例子。在Databricks的“快速入门指南”中,我们可以找到一个已注册的模型。

进入模型页面后,你会注意到所有相关的构件(Artifacts)都已注册完成。页面还提供了进行预测的能力,并显示了一个非常重要的路径(Path)。这个路径非常强大,因为它允许我们远程与这个模型进行交互。


上一部分我们看到了如何在UI中定位模型,现在我们来具体看看“加载、列出、注册和服务”这个工作流。

首先,我们可能需要查看平台上所有的实验记录。我们可以运行以下命令来列出所有MLflow实验:

# 列出所有MLflow实验
mlflow experiments list

命令执行后,会显示一个实验列表。你可以通过Databricks界面找到关心的那个实验,进而定位到对应的模型UI。由于在本例中我们已经知道了模型UI,我们可以跳过查找步骤。

回到我们的例子,我们可以直接复制模型的存储路径。然后,通过以下命令来下载这个模型:

# 下载位于指定Databricks路径的模型
mlflow models download -i <model_uri> -d /local/target/path

这个命令会将整个模型包下载到本地。


模型下载完成后,最后一步就是部署服务。这个过程非常直接。

我们只需要使用mlflow models serve命令,并指定刚才下载的模型路径即可:

# 部署(服务)下载的模型
mlflow models serve -m /local/path/to/downloaded/model --no-conda

这个命令会启动一个本地服务,托管我们从Databricks下载的模型。服务启动后,如果你想进行API调用,可以使用curl命令,也可以使用Python的requests库等工具。

# 示例:使用curl调用模型API
curl -X POST http://127.0.0.1:5000/invocations -H 'Content-Type: application/json' -d '{"data": [[1,2,3]]}'

可以看到,与远程Databricks服务器上的模型进行交互,是一个非常直观和简单的过程。


本节课中我们一起学习了在Databricks上管理机器学习模型的完整流程。我们了解了如何通过API和UI来加载注册模型,如何下载已注册的模型到本地,以及最后如何通过简单的命令将模型部署为一个可访问的API服务。这套流程使得团队协作和模型部署变得高效且标准化。

028:Databricks模型注册表

在本节课中,我们将学习Microsoft Azure Databricks平台中的模型注册表功能。我们将了解如何访问已注册的模型、查看模型版本、追溯模型来源,以及管理模型的生命周期阶段。

访问模型注册表

上一节我们介绍了Databricks的机器学习界面。本节中,我们来看看如何访问模型注册表。

在机器学习界面中,可以通过多种方式进入模型注册表。一种方式是通过右侧最近活动面板中的工件链接进入。另一种方式是向下滚动,点击“模型”图标。进入“模型”页面后,即可访问在Databricks平台中注册的所有模型。

查看模型与版本

以下是查看模型及其版本信息的步骤。

  • 在模型列表中,可以看到每个模型及其版本数量。例如,一个模型可能显示有4个版本。
  • 初始状态下,模型可能尚未设置“暂存”或“生产”等阶段标签。
  • 点击进入一个具体模型,例如“elastic wine model”。
  • 在模型详情页,选择“服务”标签页,可以看到该模型尚未启用服务功能。
  • 点击一个具体的版本号,可以查看该版本的详细信息。

追溯模型来源与复现

一个关键功能是能够追溯模型的来源。这确保了模型的可复现性。

在模型版本详情页,可以找到“源运行”的链接。点击该链接,会跳转到创建此模型版本时对应的运行记录。该记录详细展示了运行此模型所需的所有步骤和代码。这种深度集成使得模型可以被版本化、选择,并方便地进行各种操作。

例如,通过一个简单的命令行,就可以选择特定的Git仓库并重新运行此模型。

管理模型生命周期阶段

模型注册表的核心价值在于管理模型从开发到部署的生命周期。我们通过另一个例子来具体说明。

回到模型列表,查看另一个模型,例如“wine quality example”。选择其版本3,页面会显示该版本的源运行信息,同时提供“转换阶段”的功能。

这对于运维工作至关重要。例如,可以请求将某个模型从生产环境移回非生产阶段。也可以请求将模型归档。

这是一种基于阶段的生命周期管理流程。它使得组织能够协调数据科学团队和运维团队的工作,确保准确追踪生产环境中使用的是哪个模型版本,并管理模型的降级或上线流程。

总结

本节课中我们一起学习了Databricks模型注册表的核心操作。我们了解了如何访问和查看已注册的模型及其版本,如何通过“源运行”功能追溯和复现模型,以及如何使用阶段转换功能来管理模型的生命周期,从而在团队协作中确保模型部署的清晰与可控。

029:Databricks上的模型服务

在本节课中,我们将学习如何在Databricks平台上部署和提供机器学习模型服务。我们将涵盖从模型注册表中选择模型,到配置实时API或批量推理的完整流程。

模型注册表概览

上一节我们介绍了模型注册表的基本概念。本节中我们来看看如何实际使用注册表中的模型来提供服务。

在Databricks工作区中,你可以在“最近活动”中看到模型,也可以直接导航到专门的“模型”区域。

选择与部署模型

以下是部署模型的基本步骤:

  1. 在模型列表中选择目标模型,例如“elasticastic wine model”。
  2. 点击“使用此模型进行推理”的选项。

此时,你需要决定推理服务的类型。

配置推理服务类型

Databricks主要支持两种模型服务方式:批量推理和实时推理。

批量推理适用于周期性任务,例如每晚执行一次的信用风险评估。其核心操作是选择一个输入数据表进行一次性评分。

# 概念性示例:批量推理处理
process_batch_inference(input_table='nightly_transactions')

实时推理则会启动一个REST API端点,能够接收即时请求并返回预测结果。选择此选项后,系统将自动配置和启动一个服务集群。

实时服务端点管理

当你启动实时端点后,界面会进入“等待中”状态,随后系统将启动计算资源。

在端点管理界面,你可以:

  • 查看正在运行的模型版本。
  • 监控相关事件,如端点更新、集群启动。
  • 检查并配置后端集群的规格,例如可以选择基于GPU的推理实例以加速特定类型的模型。

此外,该界面的一个关键功能是允许你在不同模型版本之间切换。你可以选择部署历史版本中的任何一个。

调用服务端点

部署实时端点后,Databricks会提供详细的调用示例。

例如,你可以使用curl命令通过HTTP请求调用API:

curl -X POST -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{"dataframe_records": [<your_features>]}' https://<workspace>.cloud.databricks.com/model/<model_name>/<version>/invoke

同样,也提供了Python代码的调用方式:

import requests
response = requests.post(api_url, headers=headers, json=data)

这实现了一个“点击即服务”的在线模型部署流程。

批量推理配置

如果回到模型选择界面并选择“批量推理”,操作同样直观。

核心步骤是选择一个输入表,系统将对该表数据执行一次性批量预测操作。这为ETL管道或定期报表任务提供了便利。

总结

本节课中我们一起学习了在Databricks上进行模型服务的全过程。我们了解了如何从模型注册表中选择模型,并根据需求配置实时REST API服务或批量推理任务。平台提供了清晰的管理界面和调用示例,使得模型部署变得简单直接。此外,这些服务既可以在Databricks云端运行,也支持在本地环境中执行。

030:什么是MLOps 🚀

在本节课中,我们将要学习MLOps(机器学习运维)的核心概念、其必要性、关键组成部分以及实施策略。我们将探讨为什么需要MLOps,它与DevOps和数据Ops的关系,以及如何构建一个有效的MLOps平台。


动机与必要性

首先,我们需要考虑MLOps的动机。为什么需要MLOps?简而言之,MLOps是一种将模型操作化并投入生产环境以使其发挥价值的方法。

新冠疫情危机揭示了像MLOps这类解决方案的必要性。我们需要快速部署解决方案。此外,许多学术界人士或数据科学领域的新手难以将模型投入生产,这也是MLOps兴起的原因之一。市场上存在主要的MLOps平台,了解哪些平台有助于模型操作化非常重要。


行业趋势与背景

首先,让我们看看行业趋势。这确实很有启发性:《华尔街日报》在2020年10月16日报道,2020年云计算相关职位达到77.5万个,而2019年为40万个。观察LinkedIn可以发现,数据工程师和机器学习工程师的职位在增加,但云计算领域本身在招聘足够人才方面面临挑战。同时,数据科学职位数量在下降。这并不意味着数据科学不重要,而是意味着其他职位正成为进行数据科学工作的基础设施的一部分。


DevOps与MLOps的关系

现在,我们来看看DevOps和MLOps究竟是什么。如果没有DevOps,就不可能实现MLOps,这是一种需求层次结构。当你观察DevOps生态系统时,它涉及自动化软件工程任务、自动化基础设施部署、构建持续集成和持续交付,这些都是强制性的。一旦拥有这些,你就可以在其上构建数据自动化系统,这些系统能够利用DevOps平台。接下来,你可以进行平台自动化,使用这些平台工具,最终达到能够进行模型操作化的阶段。其核心理念是建立在越来越复杂的自动化形式之上。


持续交付与MLOps

考虑MLOps中持续交付概念的一种方式是使用多分支部署代码的理念,例如部署到主分支、预演分支和生产分支。每个分支内部都有“基础设施即代码”。本质上,环境就是一段代码,可以自动部署,并利用了“改善”(Kaizen)的概念,即软件系统的自动改进。通过使用改善理念,你能够充分利用围绕统计过程的基础设施来改进事物,这一理念源于二战后的汽车工业,这就是“改善”(日语中意为持续改进)的概念。


数据操作(DataOps)

数据操作可以类比为房屋的水管连接。如果你的房子没有水,就无法使用洗碗机、洗衣机或水疗浴缸等高级工具。数据也是如此,你需要某种复杂的系统来收集数据,这可能是午夜运行的数据收集作业。你还需要引用诸如特征存储这样的工具,在那里存储数据的精炼方面。此外,你需要使用像无服务器数据工程工具这样的工具,这样你就不必在幕后做大量繁重的工作,这些工作由平台管理。像Spark和Databricks这样的大数据处理工具也是很好的例子。最后是模型版本控制,这是数据的网络方面,你能够将不同的模型存储在数据湖中,以便能够回溯时间并重新评估你所做的工作。这就是数据操作。


平台自动化

平台自动化是更高一级的层次。这是一个SageMaker项目架构的好例子。在数据科学工作流中,我们有数据摄取、探索性数据分析、建模和得出结论。观察整个架构,这并非你想独自完成的事情,因为它是一个巨大的分布式系统。相反,你想使用一个平台。平台让你能够启动可以自动扩展和缩减的训练系统,让你能够在对象存储系统或数据湖中对模型进行版本控制和训练。最后,当模型准备好部署时,你可以设置这些推理端点,它们可以弹性扩展和缩减,并且可以在不同模型版本之间切换。你真的不想自己处理这些,而是希望使用一个平台来编排这种自动化。


MLOps的反馈循环

MLOps背后的反馈循环是“创建与重新训练”的概念。进行持续交付,审计流水线,并观察数据漂移等现象。这实际上是一个反馈循环,你不断评估训练好的模型,以确保它满足业务需求,并且当新数据进入系统时,其准确性仍然保持。


一次构建,多处部署

MLOps中另一个非常关键的概念是“一次构建,多处部署”或“一次创建,多处部署”。你为什么要多次构建同一种模型?实际上,你希望有一个系统能够利用完全相同的模型,以便它可以部署到不同的组件,如移动应用、Web应用或命令行工具。


25%法则

另一个我认为非常有趣的概念,我称之为“25%法则”。其核心理念是没有银弹。我认为学术界有很多关于以数据为中心还是以模型为中心的争论,但我会说这实际上是错误的论点。答案是,你需要所有这些方面。不幸的是,没有完美的解决方案。你需要自动化(即DevOps),需要数据自动化(即DataOps),需要模型自动化(即MLOps的概念),还需要理解业务方面,以便你能正确地定义问题,并且你的模型确实能达到业务需求,甚至能理解如何正确实施一个问题。例如,如果你去找一位放射科医生,并说我们要自动化你的工作,他们可能会告诉你,即使他们想自动化自己的工作,某些方面也有法律要求,需要人工参与。因此,“25%法则”的真正含义是,不要认为存在一个银弹,突然我们发现了一个可以切换的新二进制开关,然后MLOps就变得容易了。实际上,它并不容易。这是一种全面的方法,你需要平等地考虑这四个象限。


MLOps的用例

现在,让我们深入探讨一些MLOps的用例。我认为一个经典的用例是自动驾驶汽车。我们看到这正在形成,一方面有很多进展,但也可能存在业务框架问题,也许一些汽车公司需要专注于一条新道路,而不是试图优化一些可能永远不会完全按照他们预期的方式工作的东西。因此,这也是一个非常有趣的伦理用例。从零开始的机器学习生产是另一个经典用例。你是一名学者,你想将模型投入生产,你该怎么做?应用计算机视觉是MLOps的另一个很好的用例,我们在各处都能看到。车牌识别就是一个好例子。与现实世界的可靠性需求相比,研究部门的概念是不同的。


MLOps策略

既然我们对MLOps有了一些了解,现在让我们深入探讨MLOps策略。

首先,要再次意识到没有银弹。选择正确的技术合作伙伴非常重要,例如使用AWS SageMaker平台、Kubernetes或其他与你现有工作互补的关键解决方案。


主要与次要投资

另一个需要考虑的概念是主要投资和次要投资。就主要投资而言,这包括低成本、流行度、是否容易招聘人员、是否拥有全面的功能以及能否在其上构建抽象层。次要平台可能非常擅长解决某一特定问题,例如Databricks非常擅长Spark,Splunk非常擅长分析,Snowflake非常擅长大数据。一旦你拥有了这些组件,接下来需要考虑的是投资的概念。你是否专注于研发?你是否正在深入研究深度学习、Kubernetes、边缘计算等技术?你是否使用预训练模型?这些都是非常重要的考虑因素。

就主要考虑因素而言,一种方法是审视数据。如果我们从事数据科学,我们应该自己审视数据。就云计算而言,前两大参与者是AWS和Azure,分别占33%和21%。企业支持也是一个关键的考虑因素,行业标准认证、招聘能力、提升员工技能的能力,这些都是选择主要平台时非常重要的考虑因素。


次要考虑因素

就次要考虑因素而言,需要考虑的几点是:一个平台是否使工作的特定方面(如ETL,可能是Databricks;日志搜索,可能是Splunk;监控,可能是Datadog)变得更容易?它们是否有容易且流行的认证?因为这会使招聘变得更容易。它们是否与你的主要平台很好地集成?例如,是否有这些系统的第一方集成?


招聘与技能提升策略

招聘和技能提升策略需要考虑的另一点是:你是否在利用学习平台本身?你是否鼓励组织内的人员进行实践和自我意识?这样你就会知道自己知道什么,不知道什么。一个好的方法是设定年度和季度的学习目标。付费让人们学习,订阅像O‘Reilly或LinkedIn Learning这样的学习平台,这些都是在你组织中构建这种结构的很好的例子。


关键认证

对于MLOps,我会考虑的一些关键认证包括:AWS机器学习认证是一个很好的例子。AWS数据分析专业认证、解决方案架构师认证等。Snowflake、Databricks和Google Cloud的认证也很有趣。因此,在MLOps领域有一些非常好的行业标准认证。


未来趋势

现在,MLOps的未来趋势是什么?我认为有几个趋势相当有趣。一个是NFS Ops。你是否进行基于NFS的部署?例如,你使用GitHub,在GitHub内开发,与Cloud9协作,弹性文件系统作为单一事实来源,你可以与构建系统集成并自动部署代码,因为它们都有这个集中的事实来源。我认为我们看到越来越多这种基于文件系统的方法来进行机器学习操作,这是NFS Ops的重要组成部分。

Kubernetes和Kubeflow是另一个需要重点考虑的趋势,例如集成了ML工具的Kubeflow平台。同样,无论你认为什么是关键技术,这些都是MLOps正在出现的一些趋势。


总结

在本节课中,我们一起学习了MLOps的核心概念。我们探讨了其必要性,了解了它与DevOps和数据Ops的层次关系。我们讨论了持续交付、数据操作、平台自动化以及关键的反馈循环。我们还介绍了“一次构建,多处部署”的理念和“25%法则”。最后,我们审视了MLOps的用例、实施策略、关键认证以及未来趋势。MLOps是一个全面的方法,需要结合技术、数据和业务理解,才能成功地将机器学习模型投入生产并持续创造价值。

031:探索开源MLflow框架 🚀

在本节课中,我们将要学习MLflow,一个开源的模型追踪与版本控制系统。它最初由Databricks开发,但也可以独立使用。MLflow提供了一系列强大的功能,能帮助我们高效地管理机器学习生命周期。

概述

MLflow是一个用于管理端到端机器学习生命周期的开源平台。它主要包含四个组件:追踪项目模型模型注册表。本节课我们将通过官方快速入门指南,实际操作并探索其核心功能。

安装与快速入门

首先,我们需要安装MLflow。这是使用它的第一步。

pip install mlflow

安装完成后,我们可以开始探索其功能。MLflow的官方仓库提供了丰富的示例代码,是学习的好起点。

探索追踪API与用户界面

上一节我们介绍了如何安装MLflow,本节中我们来看看它的核心功能之一:实验追踪。

MLflow的追踪API允许我们记录实验的指标、参数和输出文件(即“工件”)。例如,你可以记录模型训练的最后时间、使用的超参数等。

如果你想通过图形界面查看不同的模型运行记录和版本,只需启动MLflow UI。

mlflow ui

在Github Codespaces这类环境中,启动UI后通常可以直接在浏览器中预览界面,方便我们查看和管理实验。

运行MLflow项目示例

MLflow项目提供了一种可复现的方式打包和运行代码。以下是运行项目的方法。

你可以直接指向本地的一个子目录来运行项目。

mlflow run examples/ -P alpha=0.5

更酷的是,MLflow还支持直接指向一个Github仓库的URL来运行项目,这极大地增强了协作和复现的便利性。

mlflow run git@github.com:mlflow/mlflow-example.git -P alpha=0.5 --no-conda

请注意,如果你不想使用Conda作为包管理系统,可以在命令后添加 --no-conda 参数。

训练与部署模型

MLflow同样简化了模型的训练与服务化流程。我们可以训练一个模型,然后将其部署为一个可调用的API端点。

首先,我们使用一个示例脚本训练一个模型。训练完成后,MLflow会生成一个唯一的运行ID。

python train_model.py

接着,我们可以使用这个运行ID来部署(服务化)该模型。

mlflow models serve -m runs:/<RUN_ID>/model --no-conda -p 1234

模型服务启动后,我们可以在另一个终端中使用curl命令来调用这个API端点,以获取模型的预测结果。

curl -X POST -H "Content-Type:application/json" --data '{"data": [[1,2]]}' http://127.0.0.1:1234/invocations

总结

本节课中我们一起学习了MLflow框架的基础应用。我们从安装开始,逐步探索了其追踪API用户界面,学习了如何运行本地及远程Github仓库中的MLflow项目,最后实践了模型的训练服务化部署流程。MLflow提供了一套全面的工具,能有效管理机器学习项目的实验、代码和模型,是数据工程师和科学家提升工作效率的得力助手。

032:在Databricks中运行MLflow 🚀

在本节课中,我们将学习如何在Databricks平台中进行远程实验跟踪和模型训练。我们将了解如何从本地环境或云端(如GitHub Codespaces)连接到Databricks集群,并利用其强大的计算资源来执行MLflow项目。


远程工作流概述

上一节我们介绍了MLflow的基本概念,本节中我们来看看如何将其与Databricks结合,实现远程管理。

假设我们已有一个配置好的Databricks环境。通过设置一个访问令牌(off token)并配置Databricks CLI,我们可以在另一个环境(如GitHub Codespaces、AWS、GCP、本地数据中心甚至个人笔记本电脑)中使用MLflow生态系统。随后,我们调用一个项目仓库进行训练。这个实验的所有过程都会被跟踪并记录在Databricks平台中,同时训练工作由远程集群执行。这是一个非常高效的协作模式,Databricks生态系统负责繁重的计算任务,而用户可以进行远程交互。

运行MLflow项目的机制

接下来,我们深入探讨其工作原理。首先,让我们查看Databricks官方文档,了解如何在Databricks上运行MLflow项目。

一个MLflow项目是一种以可复用方式打包数据科学代码的格式。以下是其基本结构:

  • 项目格式:可以是一个本地目录或Git仓库。
  • 项目名称:即目录名称。
  • 配置文件:通常包含一个Conda环境文件和一个Python入口文件。

这构成了我们所需的基本配置。

执行前的关键配置

为了运行项目,你需要执行一个特定的命令。在此之前,有几个关键点需要注意:

以下是运行前必须完成的配置步骤:

  1. 获取Databricks集群URL:你需要知道Databricks集群运行位置的UI地址,这可以在管理员控制台中找到。
  2. 准备集群配置:你需要一个指向该集群的配置文件。配置过程很直接,例如选择Spark版本(如7.3)、工作节点数量(如1个)和节点类型。请根据你的项目需求选择合适的Spark版本。
  3. 安装MLflow:确保你的本地环境已通过pip install mlflow安装了MLflow。
  4. 设置Databricks CLI:这是实现远程连接的核心。

配置Databricks CLI

让我们快速了解一下如何设置Databricks CLI。

主要步骤是在你的代码仓库或本地目录中,于主目录下创建一个名为.databrickscfg的文件。文件中需要填入你的Databricks工作区URL和你在管理员界面创建的访问令牌。你可以参考文档完成此步骤,但这基本上是全部所需配置。

在Databricks UI中创建实验

完成CLI配置后,我们可以在Databricks UI中创建一个实验。

进入Databricks环境,找到创建实验的界面。点击“创建空白实验”,系统会生成一个实验ID。这个ID至关重要,它将用于在远程命令中指定实验位置。在本例中,我们将使用一个已创建的实验ID。

执行远程训练运行

现在,我们继续按照文档指示操作。首先,确保已导出MLflow的跟踪URL环境变量。

关键命令如下:我们可以通过mlflow run命令运行一个示例项目,同时传入集群配置文件(cluster-spec.json)和上一步获取的实验ID

让我们转到GitHub查看示例。这里有一个准备好的配置cluster-spec.json,其中指定了我所需的节点类型和构建此演示时的最新Spark版本。

执行过程非常简单直接。只需运行以下格式的命令:

mlflow run https://github.com/.../project-name --backend databricks --backend-config cluster-spec.json --experiment-id <你的实验ID>

运行此命令后,它会拉取项目,并利用指定的Databricks集群执行远程训练任务。命令行会显示进度,例如“项目已存在”、“运行入口点”、“提交运行以执行项目”、“启动中”等。

查看与使用结果

执行完成后,我们可以回到Databricks UI查看这次特定的运行记录。在实验界面,可以看到最新的运行记录,包括代码版本、参数、指标等所有项目信息。

此外,我们还可以查看训练生成的模型、评估指标,并可以直接将此模型用于推理预测。这为实现端到端的机器学习流程提供了极大便利。


总结

本节课中我们一起学习了如何远程与Databricks集群交互以运行MLflow项目。整个过程只需要一个访问令牌(off token)和在本地进行少量配置。这为数据科学家和工程师提供了灵活性,可以在自己熟悉的环境中开发,同时利用云端Databricks的强大计算能力进行模型训练和实验管理。

033:端到端Databricks MLflow工作流 🚀

在本节课中,我们将学习如何构建一个端到端的MLOps模型工作流,它结合了Databricks和MLflow。我们将看到,即使模型最初在Databricks平台上开发和注册,你也可以利用MLflow的API,轻松地将模型部署到其他云平台或环境中。

概述

我们将从一个具体的例子开始,展示如何将Kaggle上的一个分类项目数据上传到Databricks,利用其AutoML功能进行实验,注册最佳模型,并最终通过多种方式部署和调用该模型。核心在于理解MLflow的模型注册和API调用机制,这为模型提供了跨平台的灵活性。

端到端工作流详解

上一节我们介绍了MLflow的基本概念,本节中我们来看看一个结合Databricks的具体实现流程。

1. 数据准备与模型开发

首先,可以从Kaggle等平台获取数据集。将数据集上传至Databricks后,可以利用DBFS(Databricks文件系统)和用户界面创建数据表。

接着,可以创建一个AutoML实验来自动化模型训练和选择过程。实验完成后,系统会标识出性能最佳的模型。

2. 模型注册与管理

实验完成后,下一步是注册这个最佳模型。在Databricks中注册模型意味着为其创建一个可追踪、可版本化的记录。

注册模型后,可以选择通过Databricks提供的内置服务端点(Serving Endpoint)将其部署为实时API,但这并非唯一选项。

3. 跨平台调用与部署

得益于MLflow的标准API,注册的模型可以脱离Databricks环境使用。以下是几种调用方式:

  • 本地调用:模型注册信息中包含了所有必要资产,如序列化的模型文件(如model.pickle)、Conda环境配置(conda.yaml)、输入示例和需求文件(requirements.txt)。这允许你在本地加载并运行模型。
  • 代码示例:注册页面通常会提供加载模型并进行预测的代码片段,支持Spark DataFrame和Pandas DataFrame两种格式。
    # 示例:加载模型并进行预测(伪代码)
    import mlflow.pyfunc
    model_uri = "models:/Your_Model_Name/Production"
    loaded_model = mlflow.pyfunc.load_model(model_uri)
    predictions = loaded_model.predict(test_data)
    
  • 云端微服务:你可以从任何云环境(如Azure、AWS Cloud9、GitHub Codespaces)通过MLflow API调用已注册的模型。例如,可以将模型打包成Docker容器,推送到AWS Elastic Container Registry (ECR),然后自动部署到AWS App Runner等服务上进行预测。

4. 实践案例:假新闻预测

让我们通过一个“假新闻预测”项目的例子来串联这些步骤。

  1. 在Databricks中完成模型训练与注册。
  2. 编写一个简单的Web服务(例如使用Flask或FastAPI),该服务接收新闻文本作为输入。
  3. 在该服务中,通过MLflow API(需使用Databricks个人访问令牌进行认证)调用之前注册的“假新闻分类”模型。
  4. 将包含“外星人即将入侵地球”这类文本的请求发送(POST)到你的预测API。
  5. API内部调用模型,并返回预测结果(例如,判定该新闻为“假”)。

如果需要直接测试生产环境的Databricks模型端点,可以使用curl命令,只需提供有效的Databricks令牌即可。

curl -X POST -H "Authorization: Bearer <你的DATABRICKS_TOKEN>" \
     -H "Content-Type: application/json" \
     https://<你的workspace>.cloud.databricks.com/model/你的模型名称/生产版本/invocations \
     -d '{"dataframe_split": {"columns": ["text"], "data": [["外星人即将入侵地球"]]}}'

5. 在GitHub Codespaces中交互

此工作流的优势在于其可移植性。你可以在完全独立的环境(如GitHub Codespaces)中设置项目,从MLflow模型仓库下载模型 artifact,然后复现在课程中学到的预测操作,无需依赖Databricks运行时环境。

总结

本节课中我们一起学习了如何构建一个以Databricks和MLflow为核心的端到端MLOps工作流。关键点在于:利用Databricks进行高效的模型开发与实验管理,然后通过MLflow的模型注册功能将模型转化为一个独立的、可通过标准API访问的资产。这使得模型部署的选择变得极其灵活,不再局限于Databricks平台本身,而是可以无缝集成到AWS、Azure、GitHub Codespaces或其他任何支持Python和HTTP请求的环境中,真正实现了“一次开发,随处部署”。

034:Databricks与MLflow的自动日志记录 📊

在本节课中,我们将要学习MLflow的模型追踪功能,特别是其自动日志记录(Auto Logging)特性。我们将了解MLflow如何帮助我们在模型开发和部署阶段追踪所有相关信息,并演示如何在Databricks环境中轻松启用这一功能。

模型追踪官方文档概览

首先,让我们查看模型追踪的官方文档。文档指出,模型追踪是理解模型在开发阶段和部署阶段所发生情况的综合解决方案的一部分。

如果我们进一步查看MLflow追踪信息,会发现实际上有几种不同的部署方法。以下是主要的几种场景:

  • 场景1:本地主机 - 所有组件(代码、API、存储)都在本地运行。
  • 场景2:SQLite本地主机 - 使用SQLite数据库在本地存储追踪信息。
  • 场景3:本地主机上的追踪服务器 - 在本地运行一个追踪服务器,类似于Databricks内部的“实验”标签页。
  • 场景4:带有后端的远程追踪服务器 - 追踪服务器部署在远程(例如云端),而训练可能在本地强大的GPU上进行。
  • 场景5:启用代理工件存储的追踪服务器 - 追踪服务器可以将数据(如模型文件)保存到云存储桶(如AWS S3)中。
  • 场景6:追踪服务器作为工件存储的代理访问主机 - 模型、镜像、配置等存储在远程主机(如SageMaker),而追踪主机可以部署在云端或第三方数据中心。

自动日志记录的核心作用

上一节我们介绍了MLflow追踪的各种架构场景。本节中我们来看看自动日志记录(Auto Logging)在其中扮演的关键角色。mlflow.autolog() 功能是实现轻松追踪的核心特性。

为了理解其工作原理,我们可以查看官方示例。将示例链接导入到Databricks环境中,并附加到集群后,可以看到步骤相当直接。

以下是启用自动日志记录的基本步骤:

  1. 导入库:首先需要导入MLflow库。
    import mlflow
    
  2. 启用自动日志:调用 autolog() 函数来启用自动追踪。
    mlflow.autolog()
    
  3. 训练模型:像平常一样运行你的机器学习代码(例如,使用scikit-learn训练一个模型)。MLflow会自动捕获相关信息。

运行示例代码后,系统会使用一个经典数据集创建训练和测试数据。当模型开始训练时,MLflow会自动记录实验过程。

在Databricks中查看追踪结果

训练完成后,我们可以点击Databricks界面中的“实验”(Experiments)标签页来查看自动记录的结果。

自动日志记录功能成功捕获了以下所有信息:

  • 超参数:模型训练所使用的所有超参数值。
  • 模型评分:评估模型性能的指标(如准确率、均方误差等)。
  • 模型链接:提供一个直接指向已保存模型本身的链接,方便后续管理和部署。

这种方法的核心理念在于,它以一种非常被动的方式记录系统发生的一切。使用MLflow日志记录几乎不需要额外努力,就能实现全面的实验追踪。

课程总结

本节课中我们一起学习了MLflow的模型追踪功能。我们首先概述了MLflow追踪的多种架构场景,从本地部署到复杂的远程云架构。接着,我们深入探讨了 mlflow.autolog() 这一核心功能,它能够自动捕获训练过程中的参数、指标和模型,极大地简化了实验管理。最后,我们在Databricks环境中实践了如何启用自动日志并查看追踪结果,验证了其高效性和便捷性。通过自动日志记录,数据工程师和科学家可以更专注于模型本身,而无需为手动记录实验细节费心。

035:数据的Kaizen方法论 🏭

在本节课中,我们将学习Kaizen方法论,这是一种源自制造业的持续改进哲学,并探讨如何将其核心原则——特别是“计划-执行-检查-行动”(PDCA)循环和“五个为什么”(5 Whys)分析法——应用于数据工程和软件开发中,以系统性地解决问题。


PDCA循环:科学方法的实践 🔄

上一节我们介绍了Kaizen的基本理念,本节中我们来看看其核心的实施框架:PDCA循环。PDCA是科学方法在制造业或软件工程领域的具体应用。

PDCA循环包含四个阶段:

  1. 计划:在此阶段,你需要识别问题。例如,我们需要构建一个查看库存的自动化工具。
  2. 执行:接下来,尝试将该解决方案付诸实践,构建初始原型。
  3. 检查:完成初始原型后,需要检查以确保它确实实现了业务目标。例如,围绕库存的自动化工具应能提供准确的库存计数。因此,你需要分析结果。
  4. 行动:如果方案确实有效,则将其作为生产设施的一个组成部分投入运行。如果无效,则需要回到计划阶段,识别问题所在,然后重复此过程。

因此,PDCA本质上是一个不断改进事物的迭代过程。这是Kaizen方法论的关键组成部分。


五个为什么分析法:追溯根本原因 🎯

理解了PDCA循环后,我们来看一个更具体的分析工具:“五个为什么”分析法。其核心是不断追问“为什么”,直至找到问题的根本原因。

以下是一个来自我职业生涯的真实且非常严重的场景示例:

我们有一些服务器会随机崩溃。

  • 第一个问题:它们为什么崩溃?
    • 答案:不确定。没有日志文件,因此无法调查崩溃原因。
  • 下一个问题:为什么没有日志文件?
    • 答案:我们发现系统使用的是临时存储(ephemeral storage),这种存储会在重启后消失。并且系统没有交换分区(swap partition),即当机器内存基本耗尽时使用的分区。
  • 下一个问题:为什么系统会使用没有交换分区的临时存储?
    • 答案:DevOps专家曾在一家顶级科技公司工作,他们说那里不使用交换分区。第二个原因是临时存储更便宜。
  • 后续问题:如果我们启用交换分区并使用EBS存储会怎样?(EBS存储是一种在重启后仍能持久保存的块存储。)
  • 最终的根本原因分析:我们能够在崩溃日志中显示存在内核恐慌和内存不足错误。这是调试问题的最后一步。
    • 最终问题:是什么导致了该错误?现在我们能看到根本原因是:Java应用服务器配置文件分配的内存超过了机器可用内存。这导致应用软件本身消耗了所有内存,并且由于没有交换分区可供写入,内核本身不得不介入。由于Java消耗了所有内存,Linux内核杀死了Java进程。最后,一个用于管理进程并自动重启它们的监控程序(supervisor)引发了竞争条件,导致机器崩溃。

通过追问这五个问题,我们找到了一个非常棘手问题的根本原因。并非所有问题都能通过五个“为什么”解决,但许多问题可以。这真正体现了Kaizen的核心原则:追溯根本原因,持续找出该原因并修复它。


总结 📝

本节课中我们一起学习了Kaizen方法论在数据工程中的应用。我们首先介绍了PDCA循环(计划-执行-检查-行动),这是一个用于持续改进的迭代框架。接着,我们深入探讨了“五个为什么”分析法,通过一个真实的服务器崩溃案例,展示了如何通过连续追问来揭示问题的根本原因,而非停留在表面症状。掌握这些系统性的问题解决方法,将帮助你更有效地构建和维护可靠的数据系统。

036:GitHub Codespaces简介 🚀

在本节课中,我们将学习如何使用GitHub Codespaces这一基于云的开发环境。我们将探索其核心功能,并演示如何利用它来高效地进行软件开发、数据工程和机器学习项目。通过本教程,你将学会如何在这个环境中导航、执行基本命令以及自定义你的工作空间。


云开发环境的优势

上一节我们介绍了云开发环境的概念,本节中我们来看看GitHub Codespaces的具体优势。

GitHub Codespaces提供了一个集成的云Shell环境。你可以直接与代码仓库交互,同时也能访问完整的开发环境。这是使用基于云环境的一个巨大优势。

  • 与AWS类似,你可以访问其服务及开发环境。
  • 与GCP类似,你可以访问其服务及开发环境。
  • 与Azure类似,你可以访问其服务及开发环境。

这确实是软件开发的一种新范式。我们将直接进入GitHub Codespaces,并了解那些能让你高效工作的功能。


创建并进入Codespace

现在,我们进入GitHub。我将创建一个新的仓库。

我们将这个仓库命名为 GitHub-Codespaces-Demo,并注明这是一个演示项目。然后,我会选择添加一个README文件和一个.gitignore文件。我通常为我的.gitignore文件选择Python模板,这能帮助我们忽略一些不必要的文件。

接着,我们点击“创建仓库”。

完成这些后,使用GitHub环境的一个好处是,我可以在其中直接进行软件开发。这对于数据工程、软件工程和机器学习工程来说,都是一个基础组成部分。

请注意,如果我点击这里的“Code”按钮,我可以选择克隆到本地,或者克隆到云环境。但我们要做的是选择“Codespaces”。

注意这里的提示:“欢迎使用云编辑。你可以在不进行本地克隆和设置的情况下编辑、调试和运行你的仓库。”这确实是软件开发的未来。

如果你要学习Bash,这里可能是最好的学习场所之一。你可以像这样设置一个临时仓库,并真正开始在这个代码空间内构建项目。原因是,它已经为你开始编写代码所需的一切做好了准备。这对于软件工程师来说,是一个理想的场景,可以让你深入其中并开始实践。


探索终端与Linux命令

让我们逐步了解你可以在终端中做些什么,以及如何使用Linux。

首先,我喜欢输入这个命令:uname -a。这个命令能让我查看操作系统的信息。

执行后,我们可以看到类似 Ubuntu 18.04 的信息,以及系统创建时间等详细信息。

接下来,我喜欢运行 ls 命令。这是一种列出我仓库内内容的方式。请注意,如果我在这里输入 pwd,我们可以看到我当前位于 /workspaces/GitHub-Codespaces-Demo 目录下。ls 命令显示这里有一个README文件。

如果我想创建一个新文件,可以使用 touch 命令。例如:touch new_file.txt

注意发生了什么:一个新文件出现在资源管理器中。如果我点击它,我可以编辑内容。例如,我可以输入“这真的很酷”并保存。

那么,如果我想从终端读取这个文件内容呢?有一个叫 cat 的命令。如果我输入 cat 然后按Tab键,它会自动补全文件名,然后让我查看该文件的内容。

对于初学者来说,这是一个非常常见的工作流程:

  • 你想知道你的操作系统是什么,所以使用 uname
  • 你想查看周围有什么,所以使用 ls,这就像打开房间的灯。
  • 你想创建一个新文件,所以使用 touch 命令。

请注意,如果我再次运行 touch new_file.txt 命令,什么也不会发生。我可以反复运行它,为什么没有变化?因为这个命令是幂等的。这意味着无论你运行多少次,它都会产生相同的效果:如果文件不存在,它会创建它;如果文件已存在,它什么都不做。Linux的很多工具都采用这种风格,为你提供这些实用的小功能。


导航与路径操作

我们还需要知道些什么呢?如果我们输入 pwd,它会显示我们所在位置的完整路径。

现在,如果我想输入 cd 命令,我可以转到另一个位置。让我们进入临时目录:cd /tmp

然后输入 pwd,注意它显示 /tmp。如果我想转到硬盘的根目录,我可以输入 cd /,再输入 pwd,它显示我在硬盘的根目录。

现在,如果我想回到工作空间 /workspaces,我们可以在这里看到路径。如果觉得有点难读,在GitHub Codespaces中,我可以点击“View”菜单,进入“Appearance”,然后调整一些显示设置,比如布局。这是很常见的操作。


自定义开发环境

另一件你可以做的事是配置你的终端,例如设置不同的快捷键绑定,或者为不同的语言进行自定义。

同样,在这个基于云的环境中,你拥有资源管理器,我可以切换它的开关。我也可以搜索文件,这非常方便。我可以调试代码,可以处理我的源代码控制(这里有一个我更改过的新文件)。我还可以与插件交互。

例如,如果我想找一个Bash相关的插件,这里有一个“Bash Beautifier”。我也可以使用其他环境,或者在这里调整设置,添加不同的命令面板。

简而言之,主要收获是:通过使用基于云的开发环境,我确实可以在这里做任何我想做的事情。

需要指出的几点是:我们目前在这个Bash工作空间内。但如果我想分割终端呢?我可以让终端并排显示,这是人们常做的事。

现在,如果我想打开另一个终端,我也可以再打开一个。注意这两个是连接在一起的,但我也可以在这里创建新标签页。

稍后我们会深入一点的是,编辑你的环境可能会很有帮助。注意我们的环境里有很多花哨的配置。如果我想稍微调整和改变一些东西呢?我可以进入我的 ~/.bashrc 文件,然后编辑提示符。人们就是通过编辑他们的 ~/.bashrc 文件来做这些设置的。你现在看到的所有这些东西实际上都已经设置好了。


创建和使用别名

另一件很方便的事情是,注意它已经设置了一些别名。让我们创建一个新的别名。我们将它命名为 temp_top,它的作用是切换到 /tmp 目录。

我将这样写:alias temp_top=‘cd /tmp’。在我做的很多项目中,我都会创建这样的别名,它们就像快捷方式或书签。

为了加载这个别名,我可以要么打开一个新的Shell(让我们先试试这个),然后输入 alias 命令,temp_top 就会出现。

或者,我可以回到之前的某个Shell,然后执行 source ~/.bashrc。这基本上是告诉你的环境重新加载配置。如果我再次输入 alias,我们可以看到它现在已经加载到这个环境里了。

现在,如果我想使用它,我只需输入 temp_top。看,它在我的环境中生效了。


编写并运行Bash脚本

因此,我强烈推荐使用基于云的开发环境,比如GitHub Codespaces或AWS Cloud Shell。总的来说,这能让你亲身体验使用Bash工作,并且你可以开始配置环境。这些都是可丢弃的环境,你不必担心弄坏任何东西,一切都为你设置好了。

事实上,与传统开发方式相比,我们还可以在这里创建一个“Hello World”脚本。让我们创建一个名为 hello.sh 的文件:touch hello.sh

然后,我可以在里面输入:echo “Hello World”。这样,我们的Bash脚本就准备好了。

我该如何运行它呢?我只需输入:bash hello.sh。看,“Hello World”打印出来了。


总结 🎯

本节课中,我们一起学习了GitHub Codespaces这一强大的云开发环境。我们了解了其核心优势,创建并进入了一个Codespace,探索了基本的Linux终端命令(如 uname, ls, pwd, cd, touch, cat),学习了如何导航文件系统、自定义工作环境、创建实用的命令别名,并最终编写和运行了一个简单的Bash脚本。

通过使用这种即用型、可配置且无需担心本地设置的云环境,你可以更快速、更安全地开始你的软件开发、数据工程或机器学习项目。现在,你可以自己尝试使用Codespaces,并开始运用我们在本演示中展示的一些命令了。

037:在GitHub Codespaces中编译Python 🐍

在本教程中,我们将学习如何在GitHub Codespaces环境中从零开始编译特定版本的Python。我们将使用一台16核的机器来加速编译过程,配置虚拟环境,并最终建立一个完整的Python项目工作流。

概述

有时,您可能需要特定版本的Python,或者需要以特定方式编译Python以支持某些开发库。如果无法满足这些要求,工作可能会受阻。本节将指导您从源代码编译Python,充分利用计算资源,并设置一个可复用的开发环境。

准备工作

首先,我们需要在GitHub上创建一个新的代码仓库并启动一个强大的Codespace实例。

  1. 在GitHub上创建一个名为 compile-python 的新仓库。
  2. 进入该仓库,点击“Code”按钮,然后选择“Codespaces”选项卡。
  3. 点击“Configure and create codespace”以进入高级选项。
  4. 在“Machine type”中选择可用的最大规格机器(例如16核)。
  5. 点击“Create codespace”启动实例。

启动后,您可以在浏览器中使用基于Web的VS Code界面,也可以选择在桌面版VS Code中打开。

安装编译依赖

在编译Python之前,需要安装必要的编译工具和库。以下是所需的命令列表。

sudo apt-get update
sudo apt-get install -y build-essential gdb lcov pkg-config \
    libbz2-dev libffi-dev libgdbm-dev libgdbm-compat-dev liblzma-dev \
    libncurses5-dev libreadline6-dev libsqlite3-dev libssl-dev \
    lzma lzma-dev tk-dev uuid-dev zlib1g-dev

运行这些命令以确保系统已更新并安装了所有必需的开发包。

下载Python源代码

接下来,我们需要从Python官方网站下载所需版本的源代码。

  1. 访问 python.org/downloads
  2. 找到最新的稳定版(非测试版),例如 Python 3.10.5。
  3. 右键点击“Gzipped source tarball”链接,复制其地址。
  4. 回到Codespace终端,使用 wget 命令下载该文件。
wget https://www.python.org/ftp/python/3.10.5/Python-3.10.5.tgz

下载完成后,解压源代码包。

tar xzvf Python-3.10.5.tgz

可以删除压缩包以节省空间,然后进入解压后的目录。

rm Python-3.10.5.tgz
cd Python-3.10.5

配置与编译

现在,我们进入核心的编译步骤。首先运行配置脚本,然后使用 make 命令进行编译。

运行配置命令,为编译过程生成合适的Makefile。

./configure --enable-optimizations

配置完成后,使用 make 命令并指定 -j 参数来充分利用所有CPU核心进行并行编译,这将显著加快速度。

make -j 16

此时,您可以使用 htop 等工具观察所有CPU核心是否已被充分利用。编译完成后,系统会运行一系列测试,这些测试通常是单线程的,因此会看到CPU使用率下降。

安装与设置环境

编译和测试通过后,就可以安装新编译的Python了。

使用以下命令进行安装,这会将Python可执行文件安装到系统目录。

sudo make altinstall

安装完成后,默认的系统Python版本可能仍未改变。为了使用新编译的版本,有几种方法。

方法一:直接调用
通过完整路径调用新安装的Python。

/usr/local/bin/python3.10

方法二:创建别名
编辑 ~/.bashrc 文件,为 python 命令创建一个别名,指向新版本。

vim ~/.bashrc
# 在文件末尾添加
alias python=‘/usr/local/bin/python3.10’

保存文件后,运行 source ~/.bashrc 使更改生效。

方法三:使用虚拟环境
这是推荐的做法,可以为项目创建独立的Python环境。

python3.10 -m venv ~/venv
source ~/venv/bin/activate

同样,可以将激活虚拟环境的命令添加到 ~/.bashrc 中,以便每次打开shell时自动激活。

echo ‘source ~/venv/bin/activate’ >> ~/.bashrc
source ~/.bashrc

建立Python项目模板

环境准备好后,我们可以建立一个标准的Python项目结构。

创建项目所需的基础文件。

touch requirements.txt
touch Makefile

以下是一个简单的 Makefile 示例,包含安装依赖、测试、代码格式化等常用任务。

install:
    pip install --upgrade pip
    pip install -r requirements.txt

test:
    pytest

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/cc8a9d3d32954533385a20313b85cdcf_12.png)

format:
    black .

lint:
    flake8 .

all: install test format lint

requirements.txt 中,可以列出项目依赖,例如 ludwig。然后运行 make install 来安装它们。

集成GitHub工作流

最后,我们可以将代码提交到GitHub,并设置持续集成(CI)来自动化测试。

  1. 将必要的文件(如 Makefile, requirements.txt, .gitignore)添加到Git仓库并提交。
  2. 在GitHub仓库页面,进入“Actions”选项卡。
  3. 创建一个新的workflow,配置它在每次推送时运行 make install 等命令。
  4. 在workflow配置中,可以指定使用的Python版本矩阵,例如同时测试Python 3.9和3.10。

这样,每次代码更新都会自动触发测试,确保项目的兼容性和稳定性。

总结

在本节课中,我们一起学习了如何在GitHub Codespaces中从源代码编译Python。我们涵盖了从创建仓库、启动高性能实例、安装依赖、下载并编译Python,到设置虚拟环境、创建项目模板以及配置GitHub Actions持续集成的完整流程。通过利用云端强大的计算资源和GitHub的生态工具,您可以轻松构建和管理一个定制化、可复现的Python开发环境。

038:SageMaker Studio Lab实践指南 🧪

在本节课中,我们将系统地探索AWS SageMaker Studio Lab的功能。这是一个免费的云端机器学习开发环境,我们将了解其界面、核心功能、与Google Colab的异同,以及如何上传项目、使用GPU和自定义环境。


界面概览与基本操作 🖥️

上一节我们介绍了课程背景,本节中我们来看看SageMaker Studio Lab的默认界面。界面左侧是文件浏览器,右侧是主工作区。顶部菜单栏提供了文件、编辑、运行等选项。

以下是界面中的几个关键区域:

  • 文件浏览器:用于管理项目文件,支持上传、下载和创建文件夹。
  • 启动器:用于创建新的笔记本、终端或文本文件。
  • 属性检查器/变量窗口:用于调试时查看变量、调用堆栈和断点。

上传与运行外部笔记本 📤

了解了基本界面后,我们来看看如何导入并运行现有的Jupyter Notebook。这个功能对于复用代码和项目至关重要。

操作步骤如下:

  1. 在文件浏览器中点击“上传”按钮。
  2. 从本地计算机选择已下载的 .ipynb 格式的Notebook文件。
  3. 上传完成后,在文件列表中点击该Notebook即可在右侧工作区打开。
  4. 可以逐单元格或一次性运行所有代码。

测试GPU加速能力 ⚡

上传Notebook后,我们自然想测试环境的计算能力,特别是GPU。SageMaker Studio Lab为免费用户提供了有限的GPU使用时长。

以下是测试GPU性能的一个示例流程:

  1. 从Google Colab等平台找到一个利用GPU的示例Notebook(例如,比较TensorFlow在CPU和GPU上训练卷积神经网络的速度)。
  2. 将其下载并上传到Studio Lab。
  3. 在Notebook中,可能需要先安装必要的库,例如使用 !pip install tensorflow
  4. 运行比较代码。典型结果可能显示GPU相比CPU有显著的加速效果(例如21倍)。

注意:免费账户的GPU资源有使用时间限制,界面会显示剩余时间。

探索更多功能与限制 🔍

测试了核心的笔记本和GPU功能后,我们再来探索Studio Lab的其他功能,并了解其可能存在的限制。

Studio Lab还提供以下功能:

  • 集成终端:可以打开Linux终端,执行Shell命令,管理环境。
  • Git集成:支持克隆代码仓库,方便版本控制。
  • 环境设置:可以导出Notebook为多种格式(HTML、PDF等),并调整编辑器设置。
  • 自定义内核:支持通过Conda环境文件(environment.yml)创建包含特定依赖包的自定义Python环境。

潜在限制

  • 内存限制:在处理大型数据集或模型时,可能会遇到内存不足的错误。例如,尝试加载过大的批处理数据可能导致失败。
  • AWS凭证:终端默认未配置AWS凭证,如需与S3等服务交互,需自行配置。
  • 资源配额:每个项目有固定的存储空间(如15GB)和内存上限。

与Google Colab Pro的对比 🤔

在探索了各项功能后,我们可以将SageMaker Studio Lab与另一个流行的免费工具Google Colab进行简单对比。

主要对比点如下:

  • 核心优势:Studio Lab提供持久的项目存储,关闭运行时后文件不会丢失,而Colab(免费版)的临时文件需要手动保存到云端硬盘。
  • GPU资源:两者都为免费用户提供有限时长的GPU。Studio Lab基于AWS的G4dn实例(搭载NVIDIA T4 GPU)。
  • 内存:Colab Pro提供更大的RAM(如25GB),而Studio Lab免费版可能较少。
  • 生态集成:Studio Lab更易于与AWS生态系统(如SageMaker完整服务)未来进行衔接。

从成本角度看,Studio Lab提供的免费GPU实例具有相当高的价值。

环境自定义与高级用法 ⚙️

最后,对于希望深度定制开发环境的用户,Studio Lab支持创建自定义的Conda环境。

创建自定义环境的基本步骤是:

  1. 准备一个 environment.yml 文件,其中定义了所需的Python版本和依赖包。
  2. 在Studio Lab的终端中,使用命令 conda env create -f environment.yml 来创建环境。
  3. 创建完成后,新的内核选项会出现在Notebook的启动器中。

这允许你为不同的项目创建隔离的、可复现的软件环境。


本节课中我们一起学习了SageMaker Studio Lab的核心功能。我们实践了如何上传和运行Notebook,测试了其GPU加速能力,探索了终端、Git集成等附加功能,并将其与Google Colab进行了对比。最后,我们还了解了如何通过Conda环境文件来自定义项目环境。对于学生和机器学习初学者而言,这是一个强大且免费的实验平台。

039:Pytest大师班(可选) 🧪

在本节课中,我们将从零开始,学习如何构建一个完整的Python项目测试环境。我们将涵盖从设置本地开发环境、使用持续集成服务器,到应用Pytest的高级功能,并最终构建一个包含库、命令行工具和Web服务的真实项目。

概述:为什么需要测试?

测试是DevOps实践的核心组成部分。其核心概念是能够自动测试代码,形成一个反馈循环,即持续集成。持续集成的本质是能够快速获知代码是否正常工作。

一旦你的代码在开发环境中正常工作,下一步就是将其复制到云端或生产环境。为此,你需要:

  1. 基础设施即代码:能够定义与开发环境相似的云环境。
  2. 测试:即持续集成组件。
  3. 部署:将所有部分整合并部署到目标环境。

这就是持续交付。测试之所以重要,是因为它是持续交付的强制性组成部分。你肯定不希望将错误的代码部署到生产环境并导致服务中断。测试的本质是先在本地确保代码正常工作,然后将其可靠地复制到基于云的环境中。

第一部分:搭建本地开发环境

上一节我们介绍了测试的重要性,本节中我们来看看如何搭建一个高效的本地开发环境。

首先,我们从一个云基础的开发环境开始。目前,大多数开发者使用云基础开发环境会更好。我们将使用GitHub Codespaces,它类似于AWS Cloud9等其他环境。

创建并配置虚拟环境

在任何Python项目中,第一步通常是创建一个Python虚拟环境。这可以确保项目依赖被隔离在一个目录中,提高可靠性。

以下是创建和激活虚拟环境的步骤:

# 创建虚拟环境,将其放在主目录的隐藏文件夹中,避免意外提交到Git仓库
virtualenv ~/.venv

# 激活虚拟环境
source ~/.venv/bin/activate

# 验证当前使用的Python解释器
which python

为了在每次打开新终端时自动激活虚拟环境,可以将其添加到 ~/.bashrc 配置文件中:

# 编辑bashrc文件
vim ~/.bashrc

# 在文件末尾添加以下行
source ~/.venv/bin/activate

创建项目脚手架

接下来,我们为测试项目创建一个基础脚手架。一个最小化的项目结构通常包括以下文件:

# 使用touch命令创建空文件(幂等操作)
touch Makefile requirements.txt hello.py test_hello.py

以下是每个文件的作用:

  • Makefile:用于存放复杂的命令,方便重复调用。
  • requirements.txt:列出项目依赖的包。
  • hello.py:应用程序主文件。
  • test_hello.py:测试文件。

配置Makefile

Makefile可以极大地简化开发流程。以下是一个示例Makefile,包含了安装、测试、代码格式化和代码检查等常用任务:

install:
    pip install --upgrade pip
    pip install -r requirements.txt

test:
    python -m pytest -vvs

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_9.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_11.png)

lint:
    pylint --disable=C0114,C0116 *.py

format:
    black *.py

all: install lint test format

使用 make 命令可以查看所有可用的任务:

make

管理项目依赖

requirements.txt 文件中,我们列出项目所需的包。对于测试项目,至少需要 pytest。此外,还可以添加其他有用的工具:

pytest
pytest-cov
pylint
black
ipython

使用 make install 命令安装所有依赖。确保代码可安装是持续集成的一个重要环节。

make install

交互式调试与原型设计

iPython 是一个强大的交互式Python shell,非常适合在编写正式测试前调试代码或进行原型设计。

# 在iPython中导入模块并测试功能
from hello import more_hello
assert "hi" == more_hello()

编写第一个Pytest测试

Pytest使得编写测试变得非常简单。测试文件通常以 test_ 开头,测试函数以 test_ 开头。

test_hello.py 中:

from hello import more_hello

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_42.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_44.png)

def test_more_hello():
    assert "hi" == more_hello()

运行测试:

# 使用Makefile中定义的test任务
make test

如果测试失败,Pytest会提供清晰的错误报告,指出期望值和实际值。

集成代码质量工具

除了测试,集成代码格式化和检查工具也是最佳实践。

  • 代码检查:使用 pylintflake8 检查代码风格和潜在错误。
  • 代码格式化:使用 black 自动格式化代码,保持团队代码风格一致。
# 运行代码检查
make lint

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_56.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_58.png)

# 运行代码格式化
make format

# 运行所有任务:安装、检查、测试、格式化
make all

在提交代码前运行 make all 可以确保代码质量。

固定依赖版本

使用 pip freeze 可以生成当前环境中所有包的确切版本列表,将其写入 requirements.txt 可以确保环境的一致性。

pip freeze | grep -E "pytest|pytest-cov|pylint|black|ipython" > requirements.txt

第二部分:配置持续集成

上一节我们搭建了本地环境并编写了测试,本节中我们来看看如何配置持续集成系统,确保代码在任何地方都能正常工作。

持续集成系统的核心是构建流水线,它作为代码质量的守门员,在代码合并或部署前自动运行测试。

使用GitHub Actions

GitHub Actions是一个与GitHub深度集成的CI/CD平台。我们可以在项目根目录创建 .github/workflows/ 目录,并在其中添加YAML配置文件。

以下是一个基础的GitHub Actions工作流配置示例,它在代码推送时触发,运行与本地相同的测试任务:

name: Python application test with Github Actions

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_72.png)

on: [push]

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_74.png)

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.7", "3.8", "3.9"]

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: make install
    - name: Lint with pylint
      run: make lint
    - name: Test with pytest
      run: make test
    - name: Format code with black
      run: make format

这个配置的关键点包括:

  • 矩阵测试:可以同时测试多个Python版本,确保代码兼容性。
  • 复用Makefile:CI流水线中的步骤直接调用本地定义的 make 命令,保持了配置的一致性。

添加测试覆盖率报告

使用 pytest-cov 可以生成测试覆盖率报告。在 Makefiletest 任务中添加覆盖率参数:

test:
    python -m pytest -vvs --cov=hello --cov=greeting --cov-report=term-missing

获取状态徽章

GitHub Actions可以为项目生成状态徽章,显示构建状态。将其添加到 README.md 文件中,可以直观展示项目的健康度。

在其他云环境中验证

持续集成的目标是确保代码在任何新环境中都能轻松运行。我们可以在AWS CloudShell或Cloud9等云环境中快速验证。

# 克隆代码仓库
git clone <repository-url>
cd <project-directory>

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_101.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_103.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_105.png)

# 运行完整测试流程
make all

如果一切配置正确,新环境的搭建和测试验证将变得非常简单,这对于团队新成员快速上手至关重要。

使用AWS CodeBuild

如果你的公司使用AWS,AWS CodeBuild是一个与AWS服务深度集成的替代CI/CD方案。配置逻辑与GitHub Actions类似。

在项目根目录创建 buildspec.yml 文件:

version: 0.2

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_129.png)

phases:
  install:
    commands:
      - make install
  build:
    commands:
      - make lint
      - make test
      - make format

在AWS CodeBuild控制台创建构建项目,并链接到GitHub仓库。CodeBuild的优势在于可以轻松集成S3、EFS等其他AWS服务。

第三部分:Pytest高级功能与真实项目测试

上一节我们配置了CI/CD流水线,本节中我们将深入Pytest的高级功能,并测试一个更真实的项目,该项目包含库、Web服务和命令行工具。

测试Jupyter Notebook

数据科学和工程团队经常使用Jupyter Notebook。可以使用 nbval 工具来测试Notebook。

首先,将Notebook保存到GitHub仓库。然后安装 nbval 并添加到 requirements.txt

pip install nbval

Makefile 中添加测试Notebook的任务:

test-notebook:
    python -m pytest --nbval notebook.ipynb

nbval 会执行Notebook中的所有单元格,并像普通Pytest测试一样进行断言验证。

使用PDB进行调试

PDB是Python的内置调试器。可以在代码中插入断点进行交互式调试。

在代码中添加以下行来启动PDB:

import pdb; pdb.set_trace()

当代码执行到这一行时,会进入PDB调试会话。你也可以在运行Pytest时使用 --pdb 标志,在测试失败时自动进入PDB:

python -m pytest --pdb

为了方便,可以在 Makefile 中创建一个调试任务:

debug:
    python -m pytest -vvs --pdb

测试选择与过滤

在大型项目中,可能只需要运行特定的测试。Pytest提供了多种方式来选择要运行的测试。

  • 运行单个测试模块pytest test_hello.py
  • 运行单个测试函数pytest test_hello.py::test_more_hello
  • 运行某个目录下的所有测试pytest tests/

Makefile 中可以为常用场景创建快捷命令。

使用Fixture

Fixture是Pytest的一个强大功能,用于提供测试所需的固定环境或数据。它可以实现测试的setup和teardown逻辑。

以下是一个Fixture示例,它为一个简单的“姓名”函数提供测试数据:

import pytest

@pytest.fixture
def name_bob():
    return "Bob"

@pytest.fixture
def name_sally():
    return "Sally"

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_171.png)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_173.png)

def test_my_name_bob(name_bob):
    from greeting import my_name
    assert f"My name is {name_bob}" == my_name(name_bob)

def test_my_name_sally(name_sally):
    from greeting import my_name
    assert f"My name is {name_sally}" == my_name(name_sally)

Fixture使测试代码更清晰、更易于维护,并且可以复用。

测试Flask Web应用

对于Web服务,我们可以使用Pytest来测试Flask应用。关键是为测试创建一个Flask应用实例和测试客户端。

首先,创建一个简单的Flask应用 web.py

from flask import Flask, jsonify
from mylib.m_change import change

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_187.png)

app = Flask(__name__)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_189.png)

@app.route('/')
def index():
    return jsonify({"hello": "Bob"})

@app.route('/change/<dollars>/<cents>')
def get_change(dollars, cents):
    amount = float(f"{dollars}.{cents}")
    return jsonify(change(amount))

if __name__ == "__main__":
    app.run(debug=True, port=8080)

然后,创建对应的测试文件 test_web.py,使用Fixture来设置应用和客户端:

import pytest
import json
from web import app as flask_app

@pytest.fixture
def app():
    yield flask_app

@pytest.fixture
def client(app):
    return app.test_client()

def test_index(client):
    result = client.get('/')
    assert result.status_code == 200
    expected = {"hello": "Bob"}
    assert expected == json.loads(result.get_data(as_text=True))

def test_change(client):
    result = client.get('/change/1/34')
    assert result.status_code == 200
    # 根据change函数的实际返回值进行断言
    # 例如:assert 5 in json.loads(result.get_data(as_text=True)).values()

测试Click命令行工具

对于命令行工具,我们可以使用Click自带的测试工具 CliRunner

首先,创建一个命令行工具 cli.py

#!/usr/bin/env python
import click
from mylib.m_change import change

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_199.png)

@click.command()
@click.option('--amount', prompt='Amount', help='Amount for change calculation.')
def make_change(amount):
    """Gives correct change in coins."""
    result = change(float(amount))
    click.echo(click.style(f"Change for ${amount}:", fg='red'))
    for coin, number in result.items():
        click.echo(click.style(f"{number} {coin}", fg='green'))

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/b474a0e6453db60c238a6d55d6be3b12_201.png)

if __name__ == '__main__':
    make_change()

然后,创建测试文件 test_cli.py

import pytest
from click.testing import CliRunner
from cli import make_change

@pytest.fixture
def runner():
    return CliRunner()

def test_cli_help(runner):
    result = runner.invoke(make_change, ['--help'])
    assert result.exit_code == 0
    assert "Usage" in result.output

def test_cli_change(runner):
    result = runner.invoke(make_change, ['--amount', '1.34'])
    assert result.exit_code == 0
    # 断言输出中包含预期的内容,例如硬币数量
    assert "5" in result.output  # 示例断言

重构与代码组织

随着项目增长,良好的代码组织至关重要。将通用逻辑提取到独立的库中(例如 mylib/),然后在Web服务和命令行工具中复用,可以使代码更清晰、更易于测试。

总结

在本节课中,我们一起学习了如何从零开始构建一个具备完整测试能力的Python项目。我们从搭建本地开发环境开始,使用了云开发平台和虚拟环境。然后,我们配置了持续集成系统,包括GitHub Actions和AWS CodeBuild,实现了自动化测试和矩阵测试。接着,我们深入探索了Pytest的高级功能,如Fixture、调试和测试选择。最后,我们将所学应用于一个真实的项目,成功测试了Python库、Flask Web应用和Click命令行工具,并建立了完整的CI/CD流水线。

通过掌握这些技能,你可以在新的工作环境中快速搭建起高效、可靠的开发和部署流程,确保代码质量并加速团队协作。

040:什么是DevOps 🚀

在本节课中,我们将要学习DevOps的核心概念。我们将了解DevOps并非单一的工具或技术,而是一个融合了软件工程最佳实践、组织文化和自动化的综合性理念。


当有人提到DevOps时,其核心组成部分可以概括为三个方面。以下是其主要构成:

  1. 软件工程最佳实践:这指的是在构建项目时需要遵循的一系列标准化流程和检查清单。
  2. 组织文化:这指的是公司文化中必须包含持续改进的理念,这在日语中被称为“改善”。
  3. 自动化:这是DevOps的精髓,主要指持续集成与持续交付的概念。

如果我们将DevOps置于中心,它正是这三者的结合体,并且形成了一个反馈循环。缺少其中任何一个要素,都无法实现真正的DevOps。


上一节我们概述了DevOps的三大支柱,本节中我们来看看每个支柱的具体含义。

软件工程最佳实践指的是在开发软件时,需要遵循一套标准化的方法和检查清单,以确保代码质量和项目可维护性。

自动化的核心是CI/CD,即持续集成与持续交付。它使得代码能够被自动、频繁地集成和部署。与此紧密相关的还有基础设施即代码的概念。

文化方面,关键理念是“改善”,这个词源自日本汽车工业,意为“持续改进”。它强调团队应不断寻求优化流程和产品的方法。


本节课中我们一起学习了DevOps的基本框架。我们了解到,DevOps是一个集软件工程最佳实践、强调持续改进组织文化以及以CI/CD为核心的自动化于一体的综合性方法论。这三者相互关联,形成一个持续的反馈循环,共同推动软件开发与运维的效率和质量提升。

041:DevOps关键概念 🚀

在本节课中,我们将深入探讨DevOps的核心概念。我们将了解什么是DevOps、为什么需要它,以及如何将其核心原则应用到实际工作中。课程内容基于行业专家的著作和实践经验,旨在为初学者提供一个清晰、实用的理解框架。


什么是DevOps?🤔

上一节我们介绍了数据工程的宏观背景,本节中我们来看看DevOps的具体定义。DevOps并非单一工具或职位,而是一种融合了文化、实践和自动化的方法论。

以下是《Python for DevOps》一书中对DevOps的几点核心总结:

  • 双向协作:DevOps的核心是促进软件开发(Dev)与运维(Ops)团队之间的深度协作与沟通。未来的趋势是这两个角色的融合。
  • 快速交付:运维任务的周转时间应从“数天至数周”缩短到“数分钟至数小时”。能否在几分钟内完成软件部署,是衡量一个组织是否实践DevOps的关键指标之一。
  • 开发者深度参与:开发者需要具备运维技能,其责任不应止于编写代码,而应延伸至系统的部署与监控。DevOps是每个人的职责,而非某个特定团队的工作。
  • 运维人员编程能力:运维人员需要掌握如Bash或Python等脚本语言,以提高团队整体生产力。
  • 自动化一切:自动化是DevOps的心脏。基础设施、持续集成、持续交付、监控、自动扩缩容等所有环节都必须实现自动化。没有全流程的自动化,就不是真正的DevOps。
  • 开发者自助服务:通过“基础设施即代码”和持续交付流水线,开发者应能自助完成部署(至少到预发布环境),确保代码始终处于可部署状态。
  • 持续协作:这是一个贯穿始终的概念。开发、运维、QA、产品经理等所有角色需要持续协作,共同关注部署状态和问题反馈。
  • 流程高于层级:应避免“河马驱动开发”(Highest Paid Person‘s Opinion),即避免让高层级的个人意见随意打乱既定流程,这会导致混乱。
  • 微服务架构:业界趋势是采用微服务架构,这与AWS等云厂商倡导的DevOps理念一致。持续交付系统是其灵魂。
  • 拒绝超级英雄:依赖个别“超级英雄”加班完成神奇工作的文化是有害的。DevOps强调可重复、可持续的团队流程,而非个人英雄主义。

DevOps与MLOps的紧密联系 🔗

在了解了DevOps的基本定义后,我们来看看它在热门领域的具体体现。MLOps(机器学习运维)是目前最受关注的领域之一。

其根本在于,MLOps的根基是DevOps。如果无法持续部署软件,就不可能持续部署机器学习模型。许多来自学术界的数据科学家可能缺乏DevOps经验,这使得同时掌握DevOps和数据分析技能的人才极具价值。


DevOps的起源与核心方法 📜

接下来,我们追溯DevOps的思想源头,并学习一个强大的问题分析方法。DevOps的起源可追溯至日本汽车工业的“改善”文化,其核心是 PDCA循环

  1. 计划:识别问题,制定计划。
  2. 执行:实施解决方案。
  3. 检查:评估结果,分析数据。
  4. 处理:根据检查结果采取行动,标准化成功经验或开始新的循环。

这是所有持续改进系统的核心,也是DevOps的运作精髓。

另一个至关重要的技能是 “5个为什么”分析法,它同样是持续改进文化的一部分。该方法通过连续追问“为什么”来探究问题的根本原因。

以下是一个真实案例的简化演示:

  1. :为什么服务器会崩溃?:因为内存不足。
  2. :为什么内存不足?:因为一个Java应用被分配了超过物理机总量的内存。
  3. :为什么分配会超量?:因为配置错误。
  4. :为什么配置错误没被发现?:因为服务器使用临时存储且无交换分区,崩溃日志未保存。
  5. :为什么使用这种高风险配置?:因为一位已离职的专家曾建议“顶级公司都这么做”,且成本更低。

通过五层追问,找到了配置错误和日志缺失这两个根本原因,而非停留在“服务器崩溃”的表面现象。


DevOps最佳实践 🛠️

掌握了核心理念后,我们来看看支撑这些理念的具体技术实践。DevOps的最佳实践围绕几个关键环节构建。

持续集成

持续集成是基石。你需要一个构建系统,在代码合并时自动触发构建和测试,确保团队仓库中的代码始终处于健康状态。

# 示例:一个简单的CI流水线可能包含的步骤
git commit -m "新增功能"
git push origin main  # 推送触发CI
# CI服务器自动运行:代码检查 -> 单元测试 -> 构建打包

持续交付与基础设施即代码

持续交付将自动化延伸到部署环节。结合“基础设施即代码”,部署变得可重复且幂等。

  • 幂等性:无论执行多少次,基础设施代码都能使系统达到相同的目标状态。首次运行创建资源,后续运行仅做必要变更或保持不变。
  • 优势:实现了环境的一致性,并使得创建和销毁临时环境(如用于测试)变得轻而易举。

监控与日志

监控和日志记录是必须的,可以将其视为“软件系统的数据科学”。收集指标、日志,并将其可视化,通过统计分析(如识别响应时间异常)来发现问题。

安全性与自动化

在现代复杂系统中,只有通过自动化才能实现持续的安全保障。自动化部署可以确保安全策略(如防火墙规则、数据加密、最小权限原则)被一致地应用和维护。


DevOps实战场景与应用 🚀

理论需要结合实际,下面我们看两个典型的DevOps应用场景。

场景一:静态网站持续交付

这是一个经典的例子,展示了从代码提交到全球部署的完整自动化流程:

  1. 使用Hugo等工具编写静态网站源码。
  2. 代码推送到GitHub。
  3. 触发CI/CD流水线,自动构建网站。
  4. 基础设施代码将构建产物同步至AWS S3存储桶。
  5. 自动通过CDN(如CloudFront)分发,并配置DNS(如Route 53)。
  6. 最终获得一个具备全球扩展能力的网站。

场景二:容器化DevOps

容器化是当前及未来的主流方向。它将应用运行时与代码打包,确保了环境的一致性和部署的简易性。

流程简述:

  1. 代码、Dockerfile和基础设施代码一同存放在Git仓库。
  2. 推送代码触发构建。
  3. 构建系统编译镜像并推送至容器仓库(如Amazon ECR)。
  4. 云环境自动拉取新镜像并完成部署。

提升组织效能的思考 💡

在课程的最后,我们思考如何将这些概念应用于提升团队效率。避免“重新发明轮子”和“超级英雄”模式。定制化、复杂的解决方案可能短期内效果显著,但会带来长期的维护负担和知识孤岛风险。采用标准化、可自动化维护的解决方案通常更具可持续性。


开发环境演进:云端开发 🌩️

一个重要的趋势是使用云端开发环境(如GitHub Codespaces或AWS Cloud9)。这允许开发者在与生产环境高度一致的环境中编写代码,避免了“在我机器上没问题”的困境,并简化了依赖管理和环境配置,是实践DevOps文化的有力助推器。

例如,在GitHub Codespaces中,你可以快速获得一个预装Python、Docker等工具的环境,并轻松配置虚拟环境:

# 创建虚拟环境
python -m venv ~/.venv
# 在 ~/.bashrc 中配置自动激活
echo ‘source ~/.venv/bin/activate’ >> ~/.bashrc
source ~/.bashrc


总结 📝

本节课中我们一起学习了DevOps的关键概念。我们了解到DevOps是一种强调开发与运维协作、全流程自动化、持续交付与改进的文化与实践体系。其核心在于通过持续集成/持续交付流水线、基础设施即代码、全面监控以及基于云的协作环境等工具与方法,实现软件交付的快速、可靠与安全。记住,DevOps的成功依赖于团队协作和流程优化,而非个人英雄主义。掌握这些原则,将为你从事现代数据工程和软件开发奠定坚实的基础。

042:持续集成概述

在本节课中,我们将学习DevOps的核心概念之一——持续集成。我们将从搭建本地开发环境开始,逐步创建一个包含测试、代码检查和格式化的Python项目脚手架,并最终将其与GitHub Actions集成,实现自动化的构建和测试流程。


DevOps的核心概念之一是能够自动测试你的代码。这就是一个反馈循环,即持续集成。持续集成的本质是能够知道你的代码是否正常工作。一旦你确认代码在开发环境中正常工作,下一步的关键就是能否将其复制到云端或生产环境中。这就是生产环境。

为了实现这一点,你需要具备几个条件。首先,你需要能够在生产环境中进行复制。这意味着你可能需要“基础设施即代码”,以便定义与开发环境相似的云环境。其次,你需要某种形式的测试,这就是之前提到的持续集成组件。最后,在部署方面,你需要将所有部分整合起来,并将代码部署到该环境中。这可以被称为持续交付。

一旦建立了持续交付,你就能够将这些更改复制到任意数量的环境中。这就是DevOps和测试的强大之处。测试是持续交付的强制性组成部分,因为你不会希望将错误的代码复制到生产环境并导致服务中断。这就是我们关心测试的本质原因:首先让代码在本地工作,然后能够将其复制到基于云的环境中。

我认为第一步是首先让本地开发环境运行起来。我们需要确保能够实际运行任何东西。

搭建本地开发环境

大多数人可能从Github或Gitlab等平台开始。虽然还有其他源代码环境,但Github可能是最流行的,我认为它是一个很好的起点,可以用来思考项目的结构。我喜欢使用基于云的开发环境,因为这样可以轻松获得所有合适的工具。在我看来,现在大多数开发者最好在基于云的开发环境中进行开发。

其中之一是Github Codespaces。这是Github的一个功能,与AWS Cloud9等其他基于云的开发环境非常相似。我将在这里创建一个新的Codespace。这样做的好处是,如果你出于某种原因真的想在本地工作,你甚至可以在本地的VS Code桌面版中使用它。但我喜欢这些环境,因为它让云本身承担所有繁重的工作,我不必担心我的环境。现在它对我来说是完全安全的,它已经配置好,加载了扩展,一切基本上都已准备就绪,可以测试我的代码了。

创建Python虚拟环境

在这样一个新环境中,我要做的第一件事是创建一个Python虚拟环境。原因是Python是一种解释型语言,为了可靠性,Python需要能够将所有包放在一个目录中。它自带一个名为virtualenv的工具。如果我们输入virtualenv,会看到这个工具就在这里。然后,如果我们输入virtualenv --help,它会显示在这个环境中可以做的所有不同事情,包括创建虚拟环境。这个虚拟环境工具有很多功能,但我们会保持简单,只创建一个新的。一个好的惯例是这样做:virtualenv ~/.venv。这样做的原因是它不会被意外地推送到你的GitHub仓库中。如果把它放在主目录下的一个隐藏目录中,这是一个很好的地方,可以避免干扰。

创建完成后,要激活它,只需输入source ~/.venv/bin/activate。现在,如果我输入which python,可以看到我引用的是这个Python。所以,对于任何Python项目来说,第一步就是获取一个基于云的开发环境。如果你在AWS上,使用Cloud9;如果你在GitHub上,可以使用GitHub Codespaces;GCP有Cloud Shell;Azure有Cloud Channel环境。它们都非常相似。

现在我已经完成了这个设置。一个令人沮丧的问题是,如果我在这里打开一个新的终端,虚拟环境就消失了。这有点烦人。我们如何解决这个问题?幸运的是,我们可以很容易地解决,因为我可以编辑我的.bashrc文件,这是这个环境的配置文件。我认为,如果你打算在一个项目中使用这种基于云的开发环境,并且环境和项目是一对一的关系,那么每次打开新shell时都自动激活虚拟环境是个好主意。

所以,我将在这里输入vim ~/.bashrc。然后我可以按Shift+G跳到文件底部,并在这里添加一个小注释,说明我想激活我的虚拟环境。然后我只需输入那个命令。现在,如果我们打开一个新的终端,虚拟环境就自动激活了。我认为这是一个很巧妙的小技巧,可以为你省去很多麻烦。现在我们有了一个环境,状态良好,可以打开新的shell,这很好。

创建项目脚手架

我喜欢做的第一件事是创建一个项目的脚手架。对我来说,一个测试项目最基本的脚手架首先是一个Makefile。我喜欢使用Makefile的原因是,它可以将许多复杂的命令保存在这里。这将是我在项目中可以反复引用的东西,甚至可以像食谱一样不断积累。接下来我要创建的是一个requirements.txt文件,这是一个我可以引用想要安装的包的地方。这确实是我真正需要的前两个文件。然后我们也许可以创建一个测试文件和一个应用程序文件。让我们称第一个文件为hello.py,第二个文件为test_hello.py。这是一个非常标准的过程,我参与的大多数项目都使用类似的结构。

现在要做的第一件事是,这些文件都是空的,touch命令的作用就是创建空文件,它是幂等的,意味着如果我反复运行touch命令,如果文件已经存在,它不会做任何不同的事情。这是一个简洁的小命令,可以为你创建空文件。我将转到这个Makefile,需要在里面放入一些不同的组件。为了做到这一点,我可以去看看我之前设置的另一个项目,并参考一下。让我看看,我有一个叫做pytest的项目。我过去已经创建了一个Makefile。让我们看看它,看看是否能得到一些启发。很好,我有一个安装部分,一个测试部分,一个格式化部分,一个代码检查部分,然后还有一个同时运行所有这些的部分。我们可能可以直接复制这个。让我们用它作为我们的脚手架。我将回到代码空间,直接粘贴进去。这就是创建一次脚手架的好处,你几乎可以一遍又一遍地使用它。

现在让我们看看这个Makefile是如何工作的。首先,我们会看到,如果我输入make,然后输入install,它会自动补全。如果我输入make加空格加Tab,它实际上会显示所有不同的选项。这是make另一个非常酷的部分,它会自动给我一个几乎像帮助菜单的东西。这就是为什么我认为Makefile对Python开发者来说非常酷。如果你没有使用Makefile,开始将它们集成到项目中是值得的,可以节省你很多时间。

安装依赖包

现在我们可以看看requirements.txt文件,我们需要安装一些能帮助我们工作的包。首先,我认为我们要安装的一个包显然是测试库pytest。首先,我们只需放入pytest,让我们看看它是如何工作的。记住,这很简单,我总是先检查确保Python打包工具pip没有新版本。然后我输入pip install -r requirements.txt。让我们运行这个,make install。完美。现在我已经设置好了,我已经加载了pytest。我如何测试pytest是否加载了呢?我可以直接输入pytest。我想它只是--help。你可以看到它确实在运行,我已经加载了pytest。它是一个非常复杂的工具,可以做很多事情。很多测试工具都非常复杂,我可以查看所有可以用pytest做的事情。

对于我刚开始一个项目时,我可能还会开始使用其他一些东西。比如我喜欢用pylint进行代码检查,还有flake8作为替代品。还有格式化工具black,以及覆盖率工具pytest-cov,它显示我们代码的覆盖率报告,比如实际测试了多少代码。这可能是一个很好的开始,我认为这很合适。我可以再次利用Makefile的力量,只需简单地再次输入make install。好了,make install

这里有趣的是,安装是持续集成的一个重要组成部分,这可能并不直观,但确实如此。所以,当我们稍后为GitHub Actions设置构建系统时,我们要做的一件事就是实际测试包的安装,因为这是现实世界的情况。你想确保你的代码实际上是可以安装的。

现在我们已经差不多设置好了一切。我们有了运行东西的能力。也许另一个我喜欢用来调试或尝试东西的工具是ipython。我认为这会是另一个。让我们安装它,我会告诉你为什么我喜欢安装ipython。当我在调试代码或尝试东西时,能够从交互式提示符导入我的模块或其他东西,这实际上非常方便。例如,如果我要测试我的代码,我可能会先在使用模块之前用它来尝试一下。让我们在这里写点东西。让我们输入more hello,然后做一些非常简单的事情,比如说hi。现在我有一段代码在这里。那么我如何在ipython中使用这个呢?我只需输入ipython。然后我会说from hello import。看,它会为我自动补全,这很好。然后我甚至可以在编写第一个测试之前尝试我的代码。我可以说,好吧,这个函数是做什么的?让我们检查一下,如果我调用它,它会做什么?好的,它返回hi。我甚至可以尝试我可能在pytest中编写的测试。pytest使用assert语句,所以我可以在这里输入assert hi == more_hello()。这本质上就像是在原型化我的单元测试。哦,太好了,这很简单,很酷。所以,ipython是一个很好的工具,我认为它被严重低估了。很好。

编写第一个测试

现在我们有了一个测试文件,这很好。让我们继续在pytest中编写我们的第一个测试。幸运的是,用pytest编写测试非常简单,这就是为什么这么多人喜欢它。这个工具很复杂,但在pytest中编写测试却简单得离谱。记住,我们有一个test_hello.py文件。我们需要做的就是基本上做和我在ipython终端中做的同样的事情。事实上,我可以直接看下面的ipython终端,本质上那就是我需要的所有代码。所以我会说from hello import more_hello

现在,我只需要写一个assert语句。这就是测试的工作原理。所以我会写def test_more_hello(),我喜欢用模块函数来命名测试。然后我只需做同样的事情,我几乎可以剪切并粘贴下面做的同样的事情,然后粘贴进去。我们可以在这里输入assert hi == more_hello()。现在让我们运行一个测试。再次看看我们的Makefile。注意我是如何测试的:我说python -m pytest,并给它几个不同的选项,比如让它更详细,这就是那些标志的作用。然后我就这样运行这个文件。所以如果我们运行这个,我只需输入make test。我喜欢在这里做make test的原因,你可以看到它通过了,是因为它更简单,只需输入更少的代码,一遍又一遍地输入命令很烦人。你会发现,除非你在pytest中做一些非常棘手的事情,否则通常只需将其放入Makefile的测试块中,这将为你节省大量时间。

现在让我们看看如果有一个失败的测试会发生什么。那是成功的,但让我们故意制造一个失败。说test_more_hello_qu。然后显然它只返回hi。如果我们说别的呢?比如bye。我们可以在这里输入more_hello,它会自动补全。如果我再运行make test,我们会在这里得到一个失败。看,它给了我们一个报告,说系统有50%通过了,我们有一个失败。我们可以看到这里说,看,你说函数应该返回bye,但实际上它返回了hi,我们有问题了。好吧,现在也许我接下来要做的是回到我的代码,说,哦,是的,我还没写这个函数。所以让我们继续写一个说more_goodbye的函数。然后,我们会说return bye。然后如果我们回到测试文件,我可以直接导入那个文件。我们可以这样做more_goodbye。然后我可以把这个改成test_more_goodbye。像这样改变。完美,现在如果我再次运行make test。好了,我们有两个测试通过了。所以非常直观,它给你这个输出,说,哎呀,我们这里有问题,让我们去修复它。

代码检查与格式化

很好,我们已经掌握了pytest的基础知识。我个人认为,让格式化和代码检查工作起来也很好。我会称之为最佳实践清单。所以让我们再次检查代码检查是否工作。如果我们用pylint进行代码检查,注意我在这里做的是说pylint,我禁用了另外两种类型的警告,我相信这在配置中是推荐的。所以我只想看到警告和错误。我注意到,在我看来,这些是我最关心的事情。所以我要继续检查这个文件。我会再次输入make lint,因为我想让我输入的内容简洁。好了,make lint。现在,什么能让我们测试这个,看看坏的代码检查会发生什么?一个简单的方法是,如果我说var = 1,我创建了一个变量,然后在里面,我创建这个,我说var = var,做一些无意义的事情。看,如果我做make test,测试仍然通过。所以它在语法上仍然是有效的,它仍然有效,只是没有真正做任何事情,这是一种糟糕的编码技巧。你不想将一个变量重新赋值给它自己。所以如果我做make lint,现在它会说,嘿,看这个,你不能这样做,你应该小心你正在将变量赋值给它自己。这是一个警告,代码仍然有效,这不是一个错误。它也会捕获错误。所以这是一个会产生警告的无意义代码。我真的相信这对于像Python这样的语言,甚至编译语言来说,捕获警告也非常关键。为什么不听编译器的呢?我认为这是个好主意。

但现在让我们制造真正糟糕的语法。如果我在这里,我也可以说f =,然后留空。像这样,这是损坏的代码,这段代码不会执行。另一件很酷的事情是,如果我们做make lint,它实际上会显示无效的语法。所以它在这里失败了,说,看,你的代码甚至无法运行。我甚至无法得到警告,因为它甚至无法运行。它就在那里告诉我们。它说第12行。这是pylint真正强大的地方之一,它与pytest配合得很好,是互补的,或者像flake8这样的任何代码检查工具。所以它捕获了额外一层的东西,这些只是有帮助的,你想知道这些事情,尤其是在团队项目中工作。

好的,很好,这个工作了。让我们继续,再次运行make test,确保它工作良好。我们会说make lint,确保它工作得很好。然后,要获得这种初始反馈循环,唯一剩下的部分就是去格式化,让我们再次检查这是如何工作的。在这个格式化工具中,我喜欢的是它还能解决团队中的问题。当你在公司里与同事一起工作时,一个人想这样做,另一个人想那样做,这可能会非常烦人。如果你使用像这样的格式化工具,它会说,看,格式化工具说这样,所以让我们保持简单,继续使用它。所以如果我说make format,好了。现在我们可以看到它只是清理了代码,让它变得更好一点。所以我认为这样做也是个好主意。如果你愿意,你实际上可以把所有这些放在一起,你可以按照你喜欢的顺序链接它们。所以我认为这是一个相当好的顺序,我推荐这个顺序,基本上是在你将代码签入到GitHub之前,为什么不直接做make all呢?所以安装你的代码,确保你拥有所有最新版本,你也可以固定requirements.txt中的版本,我们实际上会这样做,然后测试你的代码并格式化你的代码。

让我们继续这样做,让我们说pip freeze。如果我们输入pip freeze,也许通过管道传给less,它会显示当前安装的所有版本。我们可以继续这样做,我们可以直接替换它们,我就这样做。我不喜欢直接剪切和粘贴,因为这样可能会把我不需要的东西放进去。所以我认为在这里稍微小心一点我的管理会更好。所以我会说pytestpytest-cov。很好,让我们把它们放进去。像这样,这会告诉这个仓库,你正在使用我安装的这个版本的包。这对于测试来说又很好,因为我可以测试我的代码的一个非常特定的版本。然后我们可以回到这里,我们也可以把这个版本放进去。太棒了。好了,我们的包也安装好了,这很好。现在我可以做make all了。让我们继续做make all,让我们再次检查一切是否正常。好了。所以它会安装我的软件,检查我的软件,测试我的软件,格式化。我认为这是开始你的项目的一个很好的方式,我个人高度推荐它。

集成GitHub Actions

所以让我们进入下一步,让我们推送这个代码。我会说git status,然后说git add .。然后我会说git commit -m "adding initial layout of Python project"。完美。好了,现在我要继续推送这个代码。很好。

现在我已经在这里设置好了这个初始结构,我们可以开始看下一个层次了。那就是,如果我想使用除了这个环境之外的其他环境怎么办?例如,假设你的公司使用AWS、GCP或Azure,那么你该怎么做?有几件事我推荐。一是如果我们回到这个图,记住这个想法是你在本地测试,你的代码工作正常,这很好。但你也希望有能力部署到其他环境。所以这就是构建系统发挥作用的地方。构建系统基本上将是守门人,允许你在使用之前再次检查一切是否正常。

因为我们还没有设置构建系统,在我们解决这个问题之前,先不要进入云环境。我要做的是转到GitHub。我要回到我们的仓库,然后设置这个。所以让我们继续,说pytest tips and tricks。现在我要转到这个叫做“Actions”的部分,这将是GitHub Actions构建系统。构建系统只是运行你的代码,并允许你对其进行测试和部署,这确实是它的本质。GitHub Actions是较新的一个,而且因为它集成得很好,所以非常出色。我个人是它的忠实粉丝,我认为它很棒。关于GitHub Actions,有几点需要指出。这些工作流允许你做诸如使用Anaconda、使用Makefile(我刚刚展示给你看)以及发布Python包等事情。所以,如果你想成为一个开源软件开发人员,你可以这样做。你也可以使用其他流行的服务部署你的代码,比如Azure ACR、ECS、GKE等。这些都是使用它的好例子。此外,还有一些更抽象的例子,比如标签器或给某人分配任务。有很多很酷的东西。我认为一个好的起点是自己设置工作流,它基本上给你一个非常粗略的结构,你可以用来尝试东西。

既然我以前做过这个,我要做的是,实际上打开一个新标签页,再次复制一个我以前的版本。我想我有一个GitHub Actions的例子。我有一个之前做过的,看看布局。它是.github/workflows,然后有一个YAML文件。你可以在这里看到一个非常简单的使用GitHub Actions测试Python应用程序的例子。我们会说在推送时运行这些步骤。我们甚至可以指定操作系统。在这种情况下,它将是Ubuntu最新版。我们甚至可以指定Python版本。然后我可以告诉它做我刚刚在本地做的同样的事情。这真的就是全部,只是做同样的事情,但在云端的某个地方运行它,并确保在进入下一步之前一切都经过验证。所以让我们继续尝试这个。这看起来正是我想要的。让我们复制这个。然后我会把这个放到这个文件里。事实上,我们甚至可以称这个为testing_ci.yml或类似的东西。然后我们可以直接点击开始。这很酷,一旦你点击这里的开始,它就会开始运行我们的任务。我可以看到它在运行。所以它会执行所有步骤,它会先安装,然后检查,然后测试,然后格式化我们的代码。

很好,这看起来很不错。到目前为止,一切顺利。看起来我们状态良好。我们让所有东西都运行起来了,它甚至在这里显示了每个步骤,这对我们所有的代码都很好。然后,点击这个小菜单,说“创建状态徽章”,然后复制它,这不是一个坏主意。然后我们可以回到我们的项目,也就是这个项目。然后转到README.md文件。可能把它放在顶部,我们可以有我们的测试徽章。所以我们状态很好。我认为我们唯一没做的是,我要说git pull,这样我就能得到我刚才做的所有东西。但我们也没有做测试覆盖率标志。为了做到这一点,我们只需要在这里稍微调整一下。我相信我们可以查一下,实际上,我通常就是这样解决问题的。我只是说,pytest-cov。它在哪里,如何在命令中使用它?你只需说--cov。就是这样。这就是我需要做的全部。所以我要做类似的事情,回到这个仓库,我们只是添加一个小标志。我们只是说,在这种情况下我想覆盖什么?我只有一个非常简单的项目,叫做hello.py。让我们继续这样做。让我们再次运行make test,看看是否能得到覆盖率报告,make test。好了,现在我们有了覆盖率报告,我们有100%的测试覆盖率,这并不奇怪,因为这是一段非常简单的代码。然后说git statusgit add Makefile。好的,让我们提交这个,添加覆盖率报告。


在本节课中,我们一起学习了持续集成的基本概念和实践。我们从搭建一个基于云的Python开发环境开始,创建了包含虚拟环境、Makefile、依赖管理和测试的项目脚手架。我们实践了使用pytest编写和运行测试,利用pylint进行代码检查,以及用black格式化代码。最后,我们将这个本地工作流与GitHub Actions集成,实现了代码推送后自动运行的构建和测试流程。这套流程确保了代码质量,并为后续的持续交付打下了坚实基础。

043:在Cloud9中使用Python构建自然语言处理应用 🚀

在本节课中,我们将学习如何通过函数式编程构建一个可复用的自然语言处理(NLP)应用。我们将从核心逻辑开发开始,逐步将其封装为库,并最终映射到命令行工具和自动化工作流中。

核心概念:函数式逻辑与映射

使用函数构建应用的核心思想是:将核心逻辑封装在函数内部。这样,一段代码逻辑就可以被映射到多种不同的应用场景中。

例如,我们可以将一段NLP处理逻辑:

  • 映射到命令行工具(最简单的方式之一)。
  • 映射到交互式的IPython环境中。
  • 映射到Web框架中。
  • 映射到云函数(如AWS Lambda或GCP Cloud Functions)中。

这种“逻辑-映射”的脚手架结构,使我们能够灵活地适应不同的需求。

项目结构与环境搭建

上一节我们介绍了函数式逻辑的映射思想,本节中我们来看看如何搭建一个具体的项目。我们将回到Github Codespaces,开始构建一个项目结构。

首先,我们需要导入一个名为textblob的库,它是一个用于构建演示的简化文本处理库。

以下是安装所需库的步骤:

  1. requirements.txt文件中添加textblob
  2. 运行make install命令来安装依赖。

安装完成后,我们可以使用IPython来快速测试这个库。通过查阅文档,我们可以学习其基本用法。

获取与处理文本数据

为了测试NLP功能,我们需要一些文本数据。一个高效的方法是使用wikipedia库来自动抓取文本,这样我们就不需要手动创建测试数据了。

以下是获取和处理文本的步骤:

  1. 运行make install安装wikipedia库。
  2. 在IPython中,使用wikipedia.summary()函数搜索并获取特定主题(例如“Golden State Warriors”)的摘要文本。
  3. 将获取的文本传递给textblob库进行处理。

现在,我们可以尝试textblob提供的多种功能,例如情感分析(blob.sentiment)、词性标注(blob.tags)和名词短语提取(blob.noun_phrases)。首次使用某些功能时,可能需要下载必要的语料库。

构建可复用的NLP逻辑库

当我们拥有可以工作的代码后,下一步是将其构建成一个可复用的库。这是一个良好的实践,特别是对于功能相对独立和可重用的代码。

以下是创建NLP逻辑库的步骤:

  1. 创建一个名为nlp_logic的目录,并在其中添加__init__.py文件,使其成为一个Python包。
  2. 在该目录下创建核心逻辑文件,例如core_nlp.py
  3. 将之前在IPython中测试成功的逻辑提炼成多个函数。

我们将构建以下几个核心函数:

  • search_wikipedia(name): 在维基百科中搜索指定名称。
  • summarize_wikipedia(name): 获取指定名称的维基百科摘要。
  • get_text_blob(text): 根据输入的文本创建一个TextBlob对象。
  • get_phrases(name): 这是一个“主函数”,它封装了上述步骤:获取摘要、创建TextBlob对象,并最终返回名词短语列表。

在IPython中交互式地导入和测试这些函数,是验证逻辑正确性的强大方式。通过这种方式,我们可以在深入构建具体应用之前,就解决大部分棘手的错误和问题。

创建命令行工具

在核心逻辑函数构建并测试无误后,我们可以轻松地将其映射到不同的接口。首先,我们来创建一个命令行工具。

创建命令行工具最简单的方法之一是使用Python Fire库。它能够自动将函数转换为命令行接口,过程令人惊讶地简单。

以下是创建命令行工具的步骤:

  1. 安装fire库:make install
  2. 创建一个新的Python文件,例如wiki_phrases.py
  3. 在该文件中,导入我们之前构建的逻辑函数(例如get_phrases)。
  4. 使用fire.Fire(get_phrases)将函数暴露为命令行工具。
  5. 添加#!/usr/bin/env python作为文件首行(shebang),使其可直接执行。

现在,运行python wiki_phrases.py --help就能看到自动生成的帮助信息。通过命令行传递名称参数,如python wiki_phrases.py “Golden State Warriors”,即可运行整个流程。这展示了先构建函数逻辑,再使用工具(如Fire)进行封装所能带来的强大威力。

完善项目:代码质量与自动化

为了使项目更加专业,我们需要建立开发运维(DevOps)结构,包括代码风格检查、测试和自动化集成。

我们将引入以下几个工具:

  • pytest: 用于运行测试。
  • pytest-cov: 用于生成测试覆盖率报告。
  • pylint: 用于代码风格和静态检查。
  • black: 用于自动格式化代码。

以下是完善项目的步骤:

  1. requirements.txt中添加这些开发依赖。
  2. Makefile中添加相应的命令,例如make lint(运行pylint)、make format(运行black格式化)、make test(运行pytest并生成覆盖率报告)。
  3. 创建测试文件,例如test_core_nlp.py,并编写至少一个功能测试(例如,断言get_phrases(“Golden State Warriors”)的返回结果中包含预期的短语)。
  4. 运行make lintmake formatmake test来确保一切正常。

设置持续集成(CI)

最后,我们可以使用Github Actions为项目设置持续集成(CI)流水线。这样,每次代码推送都会自动运行代码检查、测试和格式化验证。

以下是设置CI的步骤:

  1. 在项目根目录的.github/workflows/路径下创建一个YAML文件(例如ci.yml)。
  2. 在YAML文件中定义工作流,通常包括以下步骤:
    • 设置指定版本的Python环境。
    • 安装项目依赖(make install)。
    • 运行代码检查(make lint)。
    • 运行测试(make test)。
    • 运行代码格式化检查(make format,此步骤通常用于验证代码风格,而非直接修改)。
  3. 将配置文件推送到Github仓库,Actions将自动开始运行。
  4. 根据CI运行的反馈(例如Python版本不匹配、未使用的导入等)调整代码和配置。
  5. CI通过后,可以创建一个状态徽章(Status Badge),添加到项目的README文件中,直观地展示构建状态。

本节课中我们一起学习了如何从零开始构建一个NLP应用。我们首先在IPython中交互式地探索了textblobwikipedia库,然后将核心逻辑封装成可复用的函数库。接着,我们使用Python Fire快速创建了命令行工具。最后,我们通过引入pytestpylintblack等工具和设置Github Actions CI流水线,完善了项目的代码质量和自动化流程。这种“先构建核心函数逻辑,再映射到不同接口”的开发模式,是构建灵活、可维护应用的有效方法。

044:构建持续部署的容器化FastAPI微服务 🚀

在本节课中,我们将学习如何将一个已有的NLP库代码,转化为一个可投入生产环境的、容器化的Web微服务。我们将使用FastAPI框架构建Web服务,使用Docker进行容器化,并最终将其部署到AWS云平台,实现一个具备持续部署能力的完整应用。

为了将我们的代码投入生产环境并使其可运行,我们需要构建一些额外的组件。首先,我们需要创建一个Dockerfile来将其容器化。其次,我们需要构建一个Web应用,这里我们将使用FastAPI框架。完成这些组件后,我们就可以将其推送到云端。AWS提供了一个名为Cloud 9的优秀开发环境,我们将使用它。此外,我们还可以使用一项名为App Runner的服务,这是一个在AWS生态系统中与容器配合良好的服务。因此,本节的核心逻辑是:我们有一个现成的NLP库代码,我们将把它转变为一个Web服务。

在AWS Cloud 9中设置开发环境 💻

首先,我将转到AWS控制台。在AWS服务中,我们找到Cloud 9。Cloud 9非常棒,因为它允许我们在最终将运行的环境中构建应用,操作系统和上下文环境都是一致的,角色等也是如此。

我将创建一个新的环境,命名为“NLP Web Service Fast API”。添加一个简短的描述:“用于构建容器化、持续部署的FastAPI应用”。我将选择一个性能较强的机器类型,例如c5.xlarge,因为我需要构建容器。操作系统选择Amazon Linux,然后点击下一步。

唯一必要的集成步骤是创建SSH密钥并将其添加到GitHub,这非常简单。在环境启动的同时,我可以去GitHub进行准备。进入GitHub设置,找到“SSH and GPG keys”,添加一个新的SSH密钥,将其命名为“cloud9_nlp”。

当Cloud 9环境启动后,我立即在终端中输入 ssh-keygen -t rsa 来生成SSH密钥。然后,我将公钥复制并添加到刚才在GitHub创建的密钥中。

添加密钥后,我回到我的GitHub项目仓库,复制SSH克隆链接。在Cloud 9终端中,使用 git clone 命令克隆仓库。

克隆完成后,我创建一个Python虚拟环境。命令是 python -m venv venv。然后激活虚拟环境:source venv/bin/activate。为了方便,我可以将这个激活命令添加到 ~/.bashrc 文件中。打开一个新的终端标签页,虚拟环境就会自动激活。

现在,我可以看到我们所有的代码。接下来,我会立即运行 make install 或直接运行 make all 命令,它会执行安装、测试、代码格式化等一系列步骤。这能确保在新环境中一切运行正常,没有意外。这就是测试、代码规范和持续集成的优势——它减少了工作量,而非增加。

运行顺利,代码还进行了一些格式化调整。我将这些更改提交到Git仓库:git add .git commit -m “Initial commit”。提交信息可以随意一些,因为我们只是在测试。

创建Dockerfile和FastAPI Web服务 🐳

现在,我需要创建一个Dockerfile和一个Web服务。我可以从我的GitHub其他项目中找一个FastAPI模板,因为很多代码是样板文件,重用模板是个好主意。

对于Dockerfile,我将使用一个基础镜像。这里我选择基于Amazon Linux的轻量版Lambda Python镜像。我需要确认有Python 3.9版本可用。搜索“lambda python”并排序,可以找到 public.ecr.aws/lambda/python:3.9 这个镜像。

Dockerfile的基本逻辑是:使用基础镜像,创建一个应用目录,将我们的代码复制进去,安装依赖,然后运行。这是一个简单的容器化过程。

接下来,我创建Web服务的主文件 main.py。同样,我可以从其他项目复制一个FastAPI模板代码。

模板中导入了FastAPI和Uvicorn。我将应用命名为“Hello NLP”。现在需要构建核心逻辑,并正确导入我们的NLP库。这时,我们之前构建的命令行工具就派上用场了,因为它清楚地告诉我们该如何导入。

我修改端点函数,让它接收一个字符串参数,比如叫 wiki_phrase。函数描述为“从Wikipedia名称生成名词短语”。函数内部直接调用我们NLP库中的 get_phrases(name) 函数。由于大部分工作已经完成,这里代码会很简单。

为了调试,我添加一个简单的 print 语句,当端点被调用时打印信息。

同时,我需要更新 requirements.txt 文件,添加 fastapiuvicorn 依赖。然后再次运行 make all 来确保一切正常。

理论上,现在可以通过运行 python main.py 来启动服务。在Cloud 9中,还可以使用“Preview”功能来预览运行中的应用。

测试本地FastAPI服务 🧪

服务启动后,我可以测试它。默认有一个 / 根路径返回“Hello NLP”。我们创建的端点是 /wiki_phrases/{name}。为了测试,我需要知道Wikipedia的页面命名格式。例如,“Los_Angeles_Lakers”可能带有下划线。我们可以先简单测试一下。

访问 /docs 路径,这是FastAPI自动生成的交互式API文档(Swagger UI)。这是一个杀手级功能。我可以在UI中点击我们的端点,选择“Try it out”,输入“Los_Angeles_Lakers”并执行。如果一切正常,应该能返回生成的短语。

这表示我们已经拥有了一个功能完整的Web服务端点,取得了巨大进展。我将提交这些更改:git add .git commit -m “Adding FastAPI service”,然后推送到GitHub。

部署到AWS:推送容器镜像 ☁️

现在开始部署到AWS。首先,我需要将Docker镜像推送到AWS Elastic Container Registry (ECR)。

在AWS控制台找到ECR服务,创建一个新的仓库,命名为 nlp-wikipedia-fastapi

创建仓库后,查看“Push commands”推送指令。我需要按顺序在Cloud 9终端中执行这些命令:

  1. 登录ECR:aws ecr get-login-password ... | docker login ...
  2. 构建Docker镜像:docker build -t nlp-wikipedia-fastapi .
  3. 为镜像打上ECR仓库的标签:docker tag nlp-wikipedia-fastapi:latest <仓库URI>:latest
  4. 推送镜像:docker push <仓库URI>:latest

因为使用了性能较强的机器,构建和推送过程会比较快。推送完成后,在ECR仓库中就能看到我们的镜像。为了后续演示方便,我将这个仓库设置为公开。

使用AWS App Runner进行部署 ⚡

接下来是更有趣的部分:使用AWS App Runner服务进行部署。App Runner可以直接指向我们ECR中的容器镜像。

在AWS控制台找到App Runner服务,点击“Create service”。选择源为“Container registry”,然后选择“Amazon ECR”。浏览并选择我们刚刚创建的 nlp-wikipedia-fastapi 镜像。

部署设置有两个选项:手动和自动。自动部署非常方便,它意味着如果我将来更新了代码并推送了新镜像,构建系统(如AWS CodeBuild或GitHub Actions)可以自动触发部署。对于演示,我选择手动部署。

配置服务名称,例如 nlp-wikipedia-fastapi。需要配置端口映射,我们的容器暴露的是8080端口,所以这里填8080。可以配置自动扩缩容、健康检查、安全网络和可观测性工具。对于演示,默认设置即可。

点击“Next”并创建服务。部署需要几分钟时间。App Runner会提供一个完整的HTTPS URL。在服务控制台,我们可以查看事件日志、部署日志、应用日志和监控指标(如请求数、2xx/4xx/5xx状态码)。如果开启了可观测性,还能查看服务拓扑图。这基本上是一个构建生产级Web服务的一站式解决方案。

本地验证与问题调试 🔧

在等待部署的同时,我们可以在本地验证容器。在Cloud 9中运行 docker images 列出镜像,找到我们刚构建的镜像ID。然后使用 docker run -p 8080:8080 <镜像ID> 在本地运行容器。通过Cloud 9的预览功能,可以像之前一样测试本地容器,访问 /docs 并尝试调用接口。

这时,我发现了一个问题。当我在生产环境的App Runner上测试“Los Angeles Lakers”时,返回了“Internal Server Error”。但在本地运行的容器中测试,却成功了。这帮助我们定位了一个Bug。

检查本地容器的日志,发现错误信息提示缺少NLTK的数据集。问题在于Dockerfile中没有下载必要的NLTK数据。修复方法很简单:在Dockerfile的 RUN 指令中添加下载数据的命令,例如 RUN python -m nltk.downloader punkt averaged_perceptron_tagger

修改Dockerfile后,需要重新构建、标记并推送镜像到ECR。这正体现了拥有一个自动化构建服务器的价值。我们手动执行这些命令。

重新部署并验证 ✅

镜像推送完成后,回到App Runner服务控制台,手动触发一次新的部署。部署状态会更新,我们可以从日志中观察进度:“Pulling image” -> “Start deploying” -> “Deployment succeeded”。

部署成功后,再次访问生产环境的 /docs 页面,测试“Los Angeles Lakers”。这次,请求成功并返回了名词短语列表。

同时,我们可以在App Runner的“Logs” -> “Application logs”中看到我们添加的 print 调试语句的输出,这非常有助于监控和调试。

总结 📝

本节课中,我们一起完成了一个完整的微服务生产化流程:

  1. 环境搭建:在AWS Cloud 9中设置了与生产环境一致的开发环境。
  2. 服务开发:使用FastAPI将现有的NLP库封装成RESTful Web服务端点。
  3. 容器化:编写Dockerfile,将应用及其依赖打包成可移植的容器镜像。
  4. 镜像管理:将Docker镜像推送至AWS ECR仓库进行存储和管理。
  5. 云部署:利用AWS App Runner服务,轻松地将容器镜像部署为可自动扩缩容、带监控日志的生产级Web服务。
  6. 调试与迭代:通过对比本地与生产环境,发现并修复了依赖缺失的问题,演示了真实的开发运维流程。

我们构建的这个系统具备了持续部署的潜力,只需配置自动化构建流水线,即可在代码更新时自动完成从构建、测试到部署的全过程。容器化技术确保了应用在不同环境中的一致性,是构建现代微服务的推荐方式。

045:在AWS上持续部署Hugo 🚀

概述

在本节课中,我们将学习如何使用Hugo静态网站生成器,结合AWS云服务,建立一个能够持续部署的全球性网站。我们将从本地开发环境搭建开始,逐步完成代码推送、自动构建和部署到AWS S3与CloudFront的完整流程。这套方法能让你以极低的成本,高效地传播真实、准确的信息。


重新审视技术:为传播真实信息而战

过去一二十年,我们过于看重用户增长、参与度和估值等指标。这导致了错误信息和虚假信息的泛滥。现在是时候利用我们自己的资源来传播真实的事实了。

Hugo是一个开源工具,易于部署。你无需向托管服务商付费,可以亲手搭建一个网站,并持续向全球部署准确、有意义的信息。你可以建立一个像《华尔街日报》或《纽约时报》那样规模的网站。

我的挑战是:你可以通过传播信息来改变世界,而Hugo可以成为你使用的工具之一。


Hugo网站持续部署流程总览

上一节我们介绍了Hugo的使命,本节中我们来看看在AWS上实现持续部署的具体架构流程。

让我们从源头开始审视这个流程。

1. 源代码管理
首先,在源代码部分,我们可以建立一个本地服务器工作流。这个环境可以是AWS Cloud9、Github Codespaces或其他基于云的环境,也可以是你的本地桌面。我个人更喜欢使用基于云的开发环境。

我会先在本地运行所有内容,确保一切设置正确,并且能在模拟云环境中正常运行。Cloud9环境正是这样一个与后续运行环境完全一致的副本。

2. 自动化构建与部署
一旦我将代码推送到Github,构建服务器就会监听变化。每次Github中的代码发生更改,构建服务器都会触发一个新的部署流程。

这个过程的好处在于,使用AWS Cloud9环境,我可以在本地推送代码,用本地Hugo服务器测试更改,确保一切正常。或者,如果只是小的内容修改,我甚至可以直接在Github中编辑,这些更改会自动部署。

3. AWS CodeBuild 与 基础设施即代码
接下来就进入了AWS CodeBuild流程。CodeBuild可以执行一个幂等的基础设施命令

这个命令可以用C#、Python或TypeScript等语言编写。这意味着你可以以编程方式、幂等地控制部署。幂等性意味着无论你部署多少次,每次更改产生的结果都是完全相同的。这能确保你的网站始终处于稳定、甚至只读的状态,从而难以被攻破。

然后,流程会构建你的Hugo网站,并将文件同步到S3存储桶中。这将成为你网站的基础。

4. 最终配置
最后一步是使用Route 53将域名指向S3存储桶,并配置AWS CloudFront(CDN)。这个工作流的妙处在于,你可以在几秒钟内部署一切。


实战演示:我的个人网站

让我们来看看如何实际操作。以下是我的个人网站 noahgift.com 的部署方式。

核心思想是:每当我需要持续部署这个网站时,我只需要前往我的Github代码库,直接编辑网站内容、课程资料等。更改会自动部署到线上的网站。

为了展示其简单性,我甚至可以编辑README文件,只写上“bump deploy”来触发构建,而无需更改任何实际内容。

我们可以看到部署成功,并且可以实时查看构建过程的详细日志。


逐步搭建:创建开发环境

如果你想自己复现这个过程,应该怎么做呢?

首先,我建议在AWS中创建一个新环境。

  1. 进入AWS Cloud9。
  2. 创建一个新环境,命名为“Hugo”。
  3. 选择配置较高的机器(例如16GB RAM,8 CPU)以获得更快的响应速度。
  4. 选择Amazon Linux 2操作系统(这与后续AWS CodeBuild环境一致)。
  5. 设置30分钟无操作超时。
  6. 创建环境。


这样,我就可以在一个与最终构建系统(将代码推送到S3的系统)完全相同的环境中开始开发。这是AWS Cloud9环境的一大优势。


在Cloud9中安装和配置Hugo

环境准备就绪后,我们开始安装Hugo。

这个环境提供了一个Bash Shell,并且通过基于角色的权限自动设置了AWS凭证,因此我可以与整个AWS生态系统交互,甚至直接将Hugo网站同步上去。

以下是安装步骤:

  1. 访问Hugo GitHub发布页,找到最新的64位tar.gz文件,复制链接地址。
  2. 在Cloud9终端中,使用 wget 命令下载该文件。
    wget [复制的Hugo下载链接]
    
  3. 解压下载的文件。
    tar -xzf hugo_*_Linux-64bit.tar.gz
    
  4. 将Hugo二进制文件复制到系统路径。
    sudo cp hugo /usr/local/bin/
    
  5. 清理下载的压缩包,并验证安装。
    rm hugo_*_Linux-64bit.tar.gz
    which hugo
    hugo version
    


现在,Hugo已成功安装。


创建并运行你的第一个Hugo站点

接下来,我们按照Hugo官方快速入门指南创建一个新站点。

  1. 使用 hugo new site 命令创建新站点。
    hugo new site quickstart
    
  2. 进入站点目录并初始化Git仓库。
    cd quickstart
    git init
    
  3. 添加一个主题(以Ananke主题为例)。
    git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
    
  4. 将主题配置写入站点配置文件。
    echo "theme = 'ananke'" >> config.toml
    
  5. 创建第一篇博客文章。
    hugo new posts/my-first-post.md
    
  6. 关键一步:编辑刚创建的文章文件(content/posts/my-first-post.md),将文件头中的 draft: true 改为 draft: false,这样文章才会发布。然后在正文添加内容,例如“Hello World”。







本地测试与远程访问配置

现在,我们可以在本地运行服务器进行测试。

  1. 启动Hugo开发服务器。
    hugo server -D
    
    -D 参数表示包含草稿文章,但我们已将其设为非草稿,所以此参数可选。
  2. Hugo会输出一个本地地址(通常是 http://localhost:1313)。为了在Cloud9环境中测试,我们可以打开一个新的终端标签页,使用 curl 命令访问。
    curl http://localhost:1313
    
    如果看到HTML输出,说明运行正常。

为了能从外部浏览器访问这个运行在Cloud9(本质是EC2实例)上的Hugo站点,我们需要配置安全组。

  1. 进入AWS EC2控制台,找到你的Cloud9实例所属的安全组。
  2. 编辑入站规则,添加一条规则:
    • 类型:自定义TCP
    • 端口范围:1313
    • 来源:0.0.0.0/0(允许任何IP访问,仅用于测试)
  3. 保存规则。


然后,你需要让Hugo服务器绑定到所有网络接口,而不仅仅是本地回环。停止当前服务器,使用以下命令重新启动:

hugo server -D --bind=0.0.0.0 --baseURL=http://[你的EC2实例公有IP]:1313

现在,你就可以通过浏览器访问 http://[你的EC2实例公有IP]:1313 来查看网站了。在Cloud9中修改文章内容并保存,刷新浏览器页面,可以看到网站内容实时更新。




这是一个非常高效的本地开发工作流。


实现持续部署:CodeBuild 与 Buildspec.yml

当你完成本地开发后,下一步就是将其自动化。就像我做的那样,你需要将代码推送到Github仓库,并配置AWS CodeBuild。

实现自动化的“秘诀”在于一个名为 buildspec.yml 的配置文件。它完成了大部分工作。

以下是 buildspec.yml 文件的核心步骤:

version: 0.2
phases:
  install:
    commands:
      # 1. 下载并安装指定版本的Hugo
      - wget https://github.com/gohugoio/hugo/releases/download/v0.XX.X/hugo_0.XX.X_Linux-64bit.tar.gz
      - tar -xzf hugo_0.XX.X_Linux-64bit.tar.gz
      - sudo cp hugo /usr/local/bin/
  build:
    commands:
      # 2. 使用Hugo构建静态网站(生成public/目录)
      - hugo
  post_build:
    commands:
      # 3. 将构建好的文件同步到S3存储桶
      - aws s3 sync public/ s3://你的存储桶名称 --delete
      # 4. (可选) 设置缓存控制头,优化CDN缓存
      - aws s3 cp s3://你的存储桶名称 s3://你的存储桶名称 --recursive --metadata-directive REPLACE --cache-control max-age=31536000
      # 5. 使CloudFront CDN缓存失效,确保用户立即看到新内容
      - aws cloudfront create-invalidation --distribution-id 你的CloudFront分配ID --paths "/*"

这个文件定义了三个阶段:

  1. 安装:在构建环境中安装Hugo。
  2. 构建:运行 hugo 命令生成网站静态文件。
  3. 构建后:将文件同步到S3,并触发CloudFront缓存刷新。

配置AWS服务:S3、Route 53 与 IAM

要使整个流程运转起来,还需要正确配置几项AWS服务。

1. Amazon S3 存储桶

  • 创建一个S3存储桶(例如以你的网站命名)。
  • 在存储桶属性中启用“静态网站托管”
  • 在存储桶权限中,添加一个存储桶策略,允许公开读取访问(只读)。这是让外界能访问你网站的关键。

2. AWS CodeBuild 项目

  • 在CodeBuild中创建新的构建项目。
  • 将源代码源设置为你的Github仓库。
  • 选择环境镜像:托管镜像 -> Amazon Linux 2 -> 标准运行时。
  • 重要:创建一个新的服务角色,或使用现有角色。这个角色必须拥有向S3写入数据以及使CloudFront缓存失效的权限(s3:PutObject, s3:ListBucket, cloudfront:CreateInvalidation 等)。
  • 在“构建规范”部分,选择“使用 buildspec.yml 文件”。

3. AWS IAM (身份和访问管理)
你需要为CodeBuild创建一个具有足够权限的角色。

  1. 进入IAM控制台。
  2. 创建新角色,受信任实体类型选择“AWS服务”,用例选择“CodeBuild”。
  3. 附加策略:至少需要包含AmazonS3FullAccess(或更细粒度的策略)和CloudFrontFullAccess(或自定义策略)的策略。
  4. 创建角色,并在创建CodeBuild项目时选择此角色。

4. Amazon Route 53 (DNS)

  • 在Route 53中,将你的域名(或子域名)的A记录或别名记录指向S3静态网站托管端点。

5. Amazon CloudFront (CDN)

  • 创建一个CloudFront分发,源站选择你刚配置的S3静态网站托管端点。
  • 这将为你的网站提供全球加速和缓存。buildspec.yml 中的最后一条命令就是用来刷新这个CDN缓存的。


完整步骤总结

本节课中我们一起学习了在AWS上为Hugo网站搭建持续部署管道的完整过程。让我们回顾一下所有步骤:

  1. 准备AWS账户与开发环境:确保你有一个AWS账户,并启动一个Cloud9环境。
  2. 配置Git:在Cloud9中设置Git用户信息,并配置SSH密钥以便与Github通信。
  3. 安装Hugo:在Cloud9环境中下载、解压并安装最新版Hugo到 /usr/local/bin/
  4. 创建Hugo站点:使用快速入门指南创建新站点,添加主题(作为Git子模块),创建内容并运行本地服务器测试。
  5. 配置安全组:为Cloud9实例的安全组开放1313端口,以便临时远程访问测试。
  6. 手动部署测试
    • 在AWS S3上创建一个存储桶,并启用静态网站托管功能。
    • 按照AWS官方文档正确配置存储桶策略(公开只读)。
    • 你可以手动从Cloud9使用 aws s3 sync 命令将 public/ 目录同步到S3,验证网站是否能正常访问。
  7. 配置自动化构建
    • 在IAM中创建CodeBuild服务角色,赋予其访问S3和CloudFront的权限。
    • 在CodeBuild中创建构建项目,连接到你的Github仓库,使用Amazon Linux 2环境,并指定正确的服务角色。
    • 在项目设置中,确保选中“报告Git子模块”选项。
    • 在代码库根目录创建并提交 buildspec.yml 文件。
  8. 配置DNS与CDN
    • 在Route 53中将域名指向S3端点。
    • 创建CloudFront分发以加速网站,并在 buildspec.yml 中配置缓存失效步骤。
  9. 触发自动化:现在,每次你向Github仓库推送代码,CodeBuild都会自动执行构建、部署和缓存刷新流程。

通过以上步骤,你就建立了一个非常直接、高效的流程,可以搭建一个全球规模的网站,其架构能力可与大型新闻网站媲美。

祝你成功!😊

046:基于容器的持续交付

在本节课中,我们将学习如何在AWS平台上,结合容器技术构建一个完整的持续交付生态系统。我们将使用AWS Cloud9进行开发,使用ECR存储容器镜像,并通过AWS App Runner和AWS CodeBuild实现自动化部署。

概述

我们将构建一个简单的FastAPI微服务,它能够将两个数字相加。通过这个项目,我们将演示如何将本地开发的容器化应用,通过一系列AWS服务,实现从代码提交到自动部署的完整流程。核心流程包括:在Cloud9中开发并本地构建容器镜像,将镜像推送到ECR,最后通过App Runner自动部署更新。

开发与本地构建

上一节我们介绍了课程的整体目标,本节中我们来看看如何开始一个项目并进行本地构建。

首先,我们需要在AWS Cloud9环境中克隆项目代码并设置开发环境。

以下是设置开发环境的步骤:

  1. 使用 git clone 命令克隆项目仓库到本地。
  2. 创建一个Python虚拟环境以隔离项目依赖。
  3. 激活虚拟环境,并安装项目所需的包。
  4. 运行应用程序,确保它在本地可以正常工作。

完成环境设置后,我们可以使用 python main.py 命令启动服务,并通过 curl 命令测试API接口是否返回正确结果,例如 curl “http://localhost:8000/add?x=3&y=3” 应返回 6

构建并推送容器镜像到ECR

在确认应用本地运行正常后,下一步是将其容器化并推送到AWS的容器镜像仓库ECR。

以下是构建和推送镜像到ECR的步骤:

  1. 在AWS控制台创建一个新的ECR仓库。
  2. 在Cloud9终端中,使用ECR提供的命令进行身份验证。
  3. 使用 docker build 命令在本地构建Docker镜像。
  4. 使用 docker tag 命令为镜像打上符合ECR仓库地址的标签。
  5. 使用 docker push 命令将镜像推送到ECR仓库。

这个过程的核心命令序列如下:

# 1. 认证
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account-id>.dkr.ecr.<region>.amazonaws.com
# 2. 构建
docker build -t fastapi-cd .
# 3. 打标签
docker tag fastapi-cd:latest <account-id>.dkr.ecr.<region>.amazonaws.com/fastapi-cd:latest
# 4. 推送
docker push <account-id>.dkr.ecr.<region>.amazonaws.com/fastapi-cd:latest

使用App Runner自动部署

将镜像成功推送到ECR后,我们可以配置AWS App Runner来自动监听该仓库的变化并部署新版本。

以下是配置App Runner服务的步骤:

  1. 在AWS App Runner控制台创建新服务。
  2. 选择“容器注册表”作为源代码,并选择我们刚刚推送镜像的ECR私有仓库。
  3. 在部署设置中,选择“自动部署”,这样每次向ECR推送新镜像时,App Runner都会自动拉取并部署最新版本。
  4. 为服务创建一个新的IAM角色,或使用现有角色,以授予App Runner访问ECR的权限。
  5. 完成配置并创建服务。App Runner将开始从ECR拉取镜像并部署应用。

集成CodeBuild实现持续集成

为了构建一个更健壮的持续交付流程,我们可以引入AWS CodeBuild。CodeBuild可以监听代码仓库(如GitHub)的变化,自动执行测试、构建新的容器镜像并推送到ECR,从而触发App Runner的更新。

以下是配置CodeBuild的基本思路:

  1. 在AWS CodeBuild控制台创建新的构建项目。
  2. 将源代码设置为你的GitHub仓库。
  3. 在构建规范中,编写与之前本地执行类似的命令:构建Docker镜像、打标签并推送到ECR。
  4. 配置Webhook,使得每次向GitHub仓库推送代码时,都能自动触发CodeBuild项目执行。

这样,整个流程就实现了完全自动化:开发者提交代码到GitHub -> CodeBuild自动构建并推送新镜像到ECR -> App Runner检测到ECR镜像更新并自动部署新版本。

总结

本节课中我们一起学习了基于容器在AWS上实现持续交付的完整流程。我们从一个简单的FastAPI应用开始,在Cloud9中完成开发和本地测试。接着,我们将其容器化,并把镜像推送到ECR仓库。然后,我们配置了App Runner服务,使其能够自动部署ECR中的最新镜像。最后,我们探讨了如何集成CodeBuild来实现从代码提交到自动构建和部署的完整自动化流水线。这种结合了 ECRApp RunnerCodeBuild 的方案,为使用容器进行持续交付提供了一个强大而高效的“梦想场景”。

047:什么是DataOps

在本节课中,我们将要学习DataOps(数据运维)的基本概念。我们将探讨它的起源、核心思想以及它如何应用于现代数据系统,以帮助组织持续改进其数据产品的价值。

概述

DataOps,即数据运维,其理念根植于传统的DevOps。理解DataOps,首先要理解其背后的自动化与持续改进思想。

DataOps的起源与核心理念

DataOps与传统的DevOps有着深厚的历史渊源。DevOps的核心思想是自动化持续改进软件工程栈的生命周期,通过微小的、持续的变更实现渐进式优化,同时促进团队成员间的协作,打破部门间的壁垒。

DataOps本质上应用了相同的概念,但将其专门应用于数据领域。随着组织越来越多地利用数据——从历史数据到实时数据,再到预测性数据——数据系统正变得日益重要。DataOps正是继承了DevOps的历史经验,并将其应用于数据系统,从而实现持续改进。

DataOps的实践策略

从本质上思考,这是一种相当直观的策略。以下是其核心实践方向:

  • 每日与每周的渐进式改进:每一天,你的工作都应比前一天有所进步;每一周,你的数据产品都应变得更好一点。
  • 数据系统的持续增强:你的数据系统应该逐渐变得更强大、更可靠。
  • 数据产品能力的扩展:你应当能够利用这些数据产品完成更多的事情。
  • 高效的组织内沟通:你应当能够与组织内的每个人进行有效沟通。
  • 基于自动化的价值创造:设定能够提升组织价值的目标,这些目标应基于你所实现的自动化和改进。

总结

本节课中,我们一起学习了DataOps的定义。简而言之,DataOps是将DevOps的自动化、协作与持续改进理念应用于数据系统和数据工程生命周期的一种方法论,旨在通过每日每周的微小改进,不断提升数据产品的价值与团队效率。

048:使用Snowflake实现DataOps与MLOps

在本节课中,我们将跟随Snowflake的解决方案架构师Chase Rao,学习如何利用Snowflake平台实现端到端的机器学习工作流。我们将了解Snowflake的核心概念,并通过一个线性回归案例,演示如何在不将数据移出Snowflake的情况下,完成数据加载、特征工程、模型训练、部署和自动化预测。

概述:什么是Snowflake?❄️

Snowflake是一个云原生的数据平台,可以理解为集数据仓库与数据湖功能于一体的“数据湖仓”。它解决了传统架构中数据孤岛、计算资源弹性伸缩和成本控制等问题。Snowflake运行在AWS、Azure和GCP等云服务上,支持多租户和弹性计算,用户只需为实际使用的计算资源(以“积分”计费)付费。

对于初学者和教学场景,Snowflake提供了非常友好的入门途径:

  • 免费试用:任何人都可获得30天试用账户及400积分。
  • 学生优惠:凭教育邮箱可申请长达120天的试用。
  • 学习资源:通过Snowflake University和丰富的在线材料(如GitHub代码库)可以系统学习。

Snowflake核心概念与优势 🏗️

上一节我们介绍了Snowflake的基本定位,本节中我们来看看它的一些核心特性和优势。

弹性数据仓库与积分计费

Snowflake的计算单元称为“虚拟仓库”。其核心优势在于弹性:你可以根据工作负载动态调整仓库规模(从X-Small到6X-Large)和集群数量。这种设计带来了两大好处:

  1. 性能与成本优化:仅在需要时使用大规模计算,任务完成后自动缩容,避免资源浪费。
  2. 按需付费:计费基于“积分”,你只需为仓库运行的时间付费。例如,一个X-Small仓库运行1小时消耗1积分。

多层缓存机制

Snowflake的缓存机制能显著提升查询速度并降低成本:

  • 元数据缓存:对于完全相同的查询,如果在24小时内再次运行,且底层数据未变,系统会直接返回缓存结果,不产生计算费用
  • 仓库缓存:在同一仓库未关闭期间,重复查询可能利用缓存,实现亚秒级响应。
    这对于需要频繁刷新的仪表板场景尤其有利,可以预先运行查询,使全天的访问都享受缓存带来的极速体验。

数据共享与市场

获取高质量数据是数据科学项目的一大挑战。Snowflake的“数据市场”功能完美解决了这个问题:

  • 数据提供者可以创建“数据共享”,在几分钟内将数据安全地分享给其他Snowflake用户。
  • 用户可以在数据市场中探索并免费获取许多公司的数据集,这些数据会以“共享数据库”的形式出现在你的账户中,查询时才产生费用。
  • 你甚至可以向非Snowflake用户提供“读取者账户”来共享数据。

认证路径

对于希望专注于Snowflake平台的MLOps专家,有一个清晰的认证路径:

  1. SnowPro核心认证:考察Snowflake基础知识。
  2. 高级架构师认证:深入掌握架构设计。
  3. 专业认证:如数据科学家认证,涵盖机器学习等专项技能。
    建议从基础认证开始,逐步深入。

实战:在Snowflake中构建端到端ML管道 🚀

了解了Snowflake的基础后,我们进入实战环节。本节将演示一个完整的机器学习项目:预测广告渠道的营收。我们将使用Snowpark for Python,确保所有数据和计算都保持在Snowflake平台内,保障安全性与一致性。

环境设置与数据准备

首先,我们需要建立与Snowflake的连接并准备数据。

以下是创建Snowpark环境并连接Snowflake的代码:

# 创建Conda环境(示例)
# conda create -n snowpark python=3.8 -c https://repo.anaconda.com/pkgs/snowflake
# conda activate snowpark
# pip install snowflake-snowpark-python scikit-learn pandas

# 导入库并建立连接
from snowflake.snowpark import Session
import snowflake.snowpark.functions as F

connection_parameters = {
    "account": "your_account",
    "user": "your_username",
    "password": "your_password",
    "warehouse": "COMPUTE_WH",
    "database": "SNOWPARK_DEMO",
    "schema": "SAMPLE_DATA"
}
session = Session.builder.configs(connection_parameters).create()

连接成功后,我们可以从Snowflake中加载已存在的表(例如campaign_spend)为Snowpark DataFrame。Snowpark采用惰性求值,在调用.show()等触发计算的动作前,不会实际运行查询或产生费用。

# 将Snowflake中的表加载为Snowpark DataFrame
snow_df_spend = session.table("campaign_spend")
# 此时未执行查询,历史记录中无记录

# 触发计算,显示数据
snow_df_spend.show()
# 此时会执行SQL,可在查询历史中看到记录

特征工程与数据转换

数据加载后,我们需要进行特征工程。假设我们要按渠道(搜索、邮件、视频、社交媒体)统计月度成本,并与营收数据关联。

以下是进行数据聚合、透视和合并的示例代码:

# 1. 聚合月度各渠道总成本
monthly_spend = snow_df_spend.group_by(F.year("DATE").alias("YEAR"), 
                                        F.month("DATE").alias("MONTH"), 
                                        "CHANNEL") \
                             .agg(F.sum("TOTAL_COST").alias("TOTAL_COST")) \
                             .sort("YEAR", "MONTH")

# 2. 将渠道透视(Pivot)为列
# 手动列出所有渠道进行透视(若渠道很多则不便)
pivot_df = monthly_spend.pivot("CHANNEL", ['search_engine', 'email', 'video', 'social_media']) \
                        .sum("TOTAL_COST")

# 更优方案:动态获取渠道列表并自动处理列名
channel_list = monthly_spend.select("CHANNEL").distinct().collect()
channel_list = [row.CHANNEL for row in channel_list]

pivot_df = monthly_spend.pivot("CHANNEL", channel_list) \
                        .sum("TOTAL_COST")
# 移除Pivot自动添加的单引号(可选)
for col in pivot_df.columns:
    if "'" in col:
        pivot_df = pivot_df.with_column_renamed(col, col.replace("'", ""))

# 3. 加载营收数据并合并
revenue_df = session.table("monthly_revenue")
monthly_revenue = revenue_df.group_by("YEAR", "MONTH") \
                            .agg(F.sum("REVENUE").alias("REVENUE")) \
                            .sort("YEAR", "MONTH")

# 合并成本与营收特征
feature_df = pivot_df.join(monthly_revenue, ["YEAR", "MONTH"])
# 删除无关列,准备建模
feature_df = feature_df.drop("YEAR", "MONTH").dropna()

# 4. 将特征表保存回Snowflake
feature_df.write.mode("overwrite").save_as_table("marketing_budget_features")

所有这些操作在调用.show().write()等动作前,都只是构建了执行计划,并未实际消耗计算资源。

在Snowflake内训练与注册模型

特征准备完成后,我们可以在Snowflake内部训练模型。通过创建存储过程,我们将训练代码部署到Snowflake的虚拟仓库中执行,数据无需离开平台。

以下是创建训练模型存储过程的代码:

# 创建存储过程来训练模型
session.sql("CREATE OR REPLACE STAGE py_models;").collect()

# 定义训练函数
def train_revenue_prediction_model(session: Session, features_table: str) -> dict:
    # 导入所需库(这些库会在存储过程运行时在Snowflake侧加载)
    from sklearn.compose import ColumnTransformer
    from sklearn.preprocessing import PolynomialFeatures, StandardScaler
    from sklearn.pipeline import Pipeline
    from sklearn.linear_model import LinearRegression
    from sklearn.model_selection import train_test_split, GridSearchCV
    import pandas as pd
    import joblib
    
    # 从Snowflake表加载数据到Pandas DataFrame(在仓库内存中处理)
    df = session.table(features_table).to_pandas()
    
    # 定义特征(X)和目标变量(y)
    X = df.drop("REVENUE", axis=1)
    y = df["REVENUE"]
    
    # 划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    
    # 创建预处理和建模管道
    numeric_features = X.columns.tolist()
    numeric_transformer = Pipeline(steps=[
        ('poly', PolynomialFeatures(degree=2)),
        ('scaler', StandardScaler())
    ])
    preprocessor = ColumnTransformer(transformers=[
        ('num', numeric_transformer, numeric_features)
    ])
    model = Pipeline(steps=[
        ('preprocessor', preprocessor),
        ('regressor', LinearRegression())
    ])
    
    # 训练模型
    model.fit(X_train, y_train)
    
    # 评估模型
    train_r2 = model.score(X_train, y_train)
    test_r2 = model.score(X_test, y_test)
    
    # 将模型保存到Stage
    model_file = "revenue_model.joblib"
    joblib.dump(model, model_file)
    session.file.put(model_file, "@py_models", overwrite=True)
    
    return {"TRAIN_R2": train_r2, "TEST_R2": test_r2}

# 将Python函数注册为Snowflake存储过程
session.sproc.register(
    func=train_revenue_prediction_model,
    name="train_revenue_prediction_model",
    packages=["snowflake-snowpark-python", "scikit-learn", "joblib"],
    is_permanent=True,
    stage_location="@py_models",
    replace=True
)

# 调用存储过程训练模型
call_result = session.call("train_revenue_prediction_model", "marketing_budget_features")
print(f"训练完成: {call_result}")

创建预测UDF与自动化推理

模型训练并保存后,我们需要一种方式对新数据进行预测。通过创建用户定义函数(UDF),我们可以将模型加载并应用于流入Snowflake的每一行新数据。

以下是创建预测UDF的代码:

# 注册UDF用于预测
session.udf.register(
    func=lambda *args: predict_revenue(*args),
    name="predict_revenue",
    stage_location="@py_models",
    input_types=[session.sql.types.FloatType()] * 4, # 假设有4个特征
    return_type=session.sql.types.FloatType(),
    packages=["scikit-learn", "joblib"],
    is_permanent=True,
    replace=True
)

# UDF背后的预测函数
def predict_revenue(search_engine, email, video, social_media):
    import sys
    import joblib
    import os
    # 从Stage加载模型
    model_path = os.path.join(sys._xoptions["snowflake_import_directory"], "revenue_model.joblib")
    model = joblib.load(model_path)
    # 进行预测
    features = [[search_engine, email, video, social_media]]
    prediction = model.predict(features)
    return float(prediction[0])

# 在Snowpark中测试UDF
test_data = [(1500.0, 800.0, 300.0, 500.0), (2000.0, 900.0, 400.0, 600.0)]
test_df = session.create_dataframe(test_data, schema=["SEARCH_ENGINE", "EMAIL", "VIDEO", "SOCIAL_MEDIA"])
predictions = test_df.select(
    test_df["*"],
    F.call_udf("predict_revenue", 
               F.array_construct(test_df["SEARCH_ENGINE"], test_df["EMAIL"], 
                                 test_df["VIDEO"], test_df["SOCIAL_MEDIA"])).alias("PREDICTED_REVENUE")
)
predictions.show()

利用流与任务实现生产化MLOps

最后,我们将整个流程自动化,实现生产级别的MLOps。利用Snowflake的流(Stream)任务(Task),可以监听数据变化并定时触发预测。

以下是设置流和任务实现自动化预测的步骤:

  1. 创建流:监听源数据表的变化(插入、更新)。
    CREATE OR REPLACE STREAM spend_stream ON TABLE raw_spend_data;
    
  2. 创建任务:当流中有新数据时,自动合并(Merge)预测结果到目标表。
    CREATE OR REPLACE TASK predict_roi_task
        WAREHOUSE = 'COMPUTE_WH'
        SCHEDULE = 'USING CRON 0 6 * * * America/New_York' -- 每天上午6点运行
    WHEN
        SYSTEM$STREAM_HAS_DATA('spend_stream') -- 仅在流中有数据时运行
    AS
        MERGE INTO predicted_roi AS target
        USING (
            SELECT 
                s.*,
                predict_revenue(s.SEARCH_ENGINE, s.EMAIL, s.VIDEO, s.SOCIAL_MEDIA) as PREDICTED_ROI
            FROM spend_stream s
        ) AS source
        ON target.ID = source.ID
        WHEN MATCHED THEN UPDATE SET target.PREDICTED_ROI = source.PREDICTED_ROI
        WHEN NOT MATCHED THEN INSERT (ID, SEARCH_ENGINE, EMAIL, VIDEO, SOCIAL_MEDIA, PREDICTED_ROI) 
        VALUES (source.ID, source.SEARCH_ENGINE, source.EMAIL, source.VIDEO, source.SOCIAL_MEDIA, source.PREDICTED_ROI);
    
  3. 启用任务
    ALTER TASK predict_roi_task RESUME;
    

这样,每当源表有新的广告支出数据流入,系统就会自动计算预测的营收投资回报率(ROI)并更新结果表,整个过程无需人工干预,且高效利用缓存和计算资源。

总结与资源 📚

本节课中我们一起学习了如何利用Snowflake实现DataOps与MLOps。我们从Snowflake的核心概念讲起,包括其弹性架构、缓存机制和数据共享能力。随后,我们通过一个完整的线性回归案例,演示了使用Snowpark for Python在Snowflake内部进行数据准备、特征工程、模型训练、注册UDF以及通过流和任务实现自动化预测的全过程。

这种方法的核心优势在于:

  • 数据不动代码动:所有数据和计算都保持在Snowflake平台内,保障了数据安全、一致性和治理。
  • 生产就绪:原生支持调度、依赖管理和自动化,便于将实验代码转化为生产流水线。
  • 成本与性能优化:弹性伸缩、多层缓存和按需付费模型,使得处理大规模数据更加经济高效。

对于希望深入学习的同学,可以参考以下资源:

  • Snowflake University:官方学习平台,提供丰富课程和实验。
  • GitHub代码库:搜索Snowflake官方或社区提供的Snowpark示例项目,包含本课演示的完整代码。
  • 试用账户:立即注册Snowflake试用账户,亲自动手实践。

Snowflake通过Snowpark等工具,正将数据工程和机器学习工作流深度集成,为构建现代化、高效且安全的数据智能应用提供了强大的平台支撑。

049:使用Step Functions和Lambda构建云管道 🚀

在本节课中,我们将学习如何使用AWS Lambda函数和AWS Step Functions来构建一个简单的云数据处理管道。我们将从编写一个基础的Lambda函数开始,然后将其与另一个函数串联,最后使用Step Functions可视化地编排它们的工作流。


概述

我们将创建一个模拟厨师处理食材的简单管道。第一个Lambda函数(random_fruit)负责接收一种水果并表达喜好。第二个Lambda函数(chef)根据第一个函数的“喜好”结果,决定制作沙拉还是烧烤。最后,我们使用AWS Step Functions将这两个函数连接成一个自动化的工作流。


创建第一个Lambda函数:处理水果 🍎

首先,我们需要在AWS控制台中创建一个Lambda函数。Lambda函数的核心是一个简单的处理单元:它接收输入(事件),执行一些工作,然后返回输出。

以下是创建和配置random_fruit函数的步骤:

  1. 在AWS控制台导航到Lambda服务。
  2. 点击“创建函数”。
  3. 选择“从头开始创作”。
  4. 设置运行时为 Python 3.9
  5. 将函数命名为 random_fruit
  6. 点击“创建函数”。

创建完成后,我们将看到代码编辑器。Lambda为我们提供了一个基础的处理函数结构:

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

参数event包含了函数的输入数据。我们将修改这个函数,使其根据输入的水果类型返回不同的信息。

编写函数逻辑

我们将编写一个函数,检查输入事件中是否包含名为fruit的字段。如果该水果是“cherry”,则返回喜爱的信息;否则,返回不喜爱的信息。同时,我们添加一些调试信息来查看传入的事件。

以下是random_fruit函数的完整代码:

import json

def lambda_handler(event, context):
    # 从事件中获取水果名称
    fruit = event.get('fruit', '')
    
    # 调试:打印传入的事件
    print(f"Received event: {event}")
    
    # 判断逻辑
    if fruit.lower() == 'cherry':
        response_body = "I love cherry!"
    else:
        response_body = f"No thanks, I don't like {fruit}."
    
    # 返回响应
    return {
        'statusCode': 200,
        'body': json.dumps(response_body)
    }

测试函数

在部署函数之前,我们可以创建测试事件来验证其逻辑。

  1. 点击代码编辑器上方的“部署”按钮。
  2. 点击“测试”按钮,创建一个新的测试事件。
  3. 为测试事件命名,例如 test_cherry
  4. 在事件JSON中,提供输入数据:{"fruit": "cherry"}
  5. 保存并运行测试。你应该看到返回结果:"I love cherry!"
  6. 再创建一个名为 test_pear 的测试事件,输入为 {"fruit": "pear"}。运行测试后,应返回:"No thanks, I don't like pear."

现在,我们已经成功创建了第一个可以独立工作的Lambda函数。它接收一个简单的JSON输入,进行处理,并返回一个明确的输出。


创建第二个Lambda函数:厨师决策 👨‍🍳

上一节我们创建了一个能表达水果喜好的函数。本节中,我们将创建第二个函数,扮演“厨师”的角色。这个函数将接收第一个函数的输出,并据此决定制作哪种餐品。

我们将创建一个名为 chef 的新Lambda函数,其逻辑是:如果输入信息中包含“love”这个词,就决定做沙拉;否则,就做烧烤。

编写函数逻辑

按照同样的步骤创建第二个Lambda函数,命名为 chef,运行时同样选择Python 3.9。

以下是chef函数的代码:

import json

def lambda_handler(event, context):
    # 调试:打印传入的事件
    print(f"Chef received event: {event}")
    
    # 注意:event 现在是上一个Lambda函数的整个返回体
    # 我们需要解析其中的 ‘body’ 字段
    try:
        # event['body'] 是一个JSON字符串,需要先解析
        body_data = json.loads(event.get('body', '{}'))
        message = body_data if isinstance(body_data, str) else str(body_data)
    except:
        message = str(event)
    
    # 决策逻辑
    if 'love' in message.lower():
        meal_decision = "Let's make a salad."
    else:
        meal_decision = "Let's make a barbecue."
    
    # 返回响应
    return {
        'statusCode': 200,
        'body': json.dumps(meal_decision)
    }

测试串联逻辑

为了测试chef函数,我们需要模拟random_fruit函数的输出作为其输入。

  1. 部署chef函数。
  2. 创建一个新的测试事件,例如 test_salad_decision
  3. 在事件JSON中,模拟random_fruit对樱桃的响应:
    {
      "statusCode": 200,
      "body": "\"I love cherry!\""
    }
    
  4. 运行测试,应返回:"Let‘s make a salad."
  5. 再创建一个测试事件 test_barbecue_decision,模拟对梨的响应:
    {
      "statusCode": 200,
      "body": "\"No thanks, I don‘t like pear.\""
    }
    
  6. 运行测试,应返回:"Let‘s make a barbecue."

至此,我们有了两个可以独立工作且逻辑上关联的Lambda函数。接下来,我们将使用AWS Step Functions将它们正式连接成一个自动化的工作流。


使用AWS Step Functions编排工作流 ⚙️

我们已经有了两个功能明确的Lambda函数。本节中,我们将使用AWS Step Functions服务,以“低代码”或“无代码”的方式,将这两个函数可视化的串联起来,构建一个完整的管道。

Step Functions 允许你通过拖放状态(步骤)来设计工作流,并定义它们之间的执行顺序和数据传递。

创建状态机

以下是创建状态机(State Machine)的步骤:

  1. 在AWS控制台导航到 Step Functions 服务。
  2. 点击“创建状态机”。
  3. 选择“使用可视化设计器设计工作流”。
  4. 在画布上,从左侧的“操作”面板拖拽一个 Lambda函数调用 到工作区。
  5. 点击这个状态进行配置:
    • API参数 -> 函数名称:选择我们创建的 random_fruit 函数。
    • 输入:选择“使用状态输入作为有效负载”。这意味着工作流的初始输入会直接传给这个函数。
  6. 从画布右侧拖拽另一个 Lambda函数调用 状态,放在第一个状态后面。它们会自动连接。
  7. 配置第二个状态:
    • 函数名称:选择 chef 函数。
    • 输入:同样选择“使用状态输入作为有效负载”。Step Functions会自动将上一个状态(random_fruit)的输出作为这个状态的输入。

现在,你的工作流看起来应该像这样:random_fruit -> chef

定义和部署状态机

  1. 在状态机设置页面,为其命名,例如 MealGenerator
  2. 权限设置可以选择“创建新的IAM角色”,让Step Functions有权限调用指定的Lambda函数。
  3. 点击“创建状态机”。

状态机创建成功后,我们就可以执行它了。

执行和测试工作流

  1. 在状态机详情页,点击“开始执行”。
  2. 在输入框中,提供我们测试用的JSON数据,例如:{"fruit": "pear"}
  3. 点击“开始执行”。

执行开始后,你可以直观地看到每个步骤(状态)的执行情况:绿色表示成功,红色表示失败。点击每个步骤,可以查看其详细的输入输出

  • 对于输入 {"fruit": "pear"},你应该看到:
    • random_fruit 步骤的输出为:{"statusCode": 200, "body": "\"No thanks, I don‘t like pear.\""}
    • chef 步骤的输入即为上述输出,其最终输出为:{"statusCode": 200, "body": "\"Let‘s make a barbecue.\""}

这个可视化的工作流清晰地展示了数据如何从一个函数流向下一个函数,最终产生结果。这种将小型的、单一职责的函数(如Linux命令行工具)串联起来构建复杂流程的理念,是分布式计算和现代数据工程的核心思想之一。


总结 🎉

在本节课中,我们一起学习了如何使用AWS Lambda和Step Functions构建云数据管道。

我们首先创建了两个独立的Python Lambda函数:

  1. random_fruit:接收水果名称并返回喜好。
  2. chef:根据第一个函数的返回信息决定制作何种餐品。

接着,我们使用AWS Step Functions的可视化设计器,将这两个函数连接成一个有序的工作流。我们定义了状态机,并通过执行测试验证了整个管道能够按预期运行:输入一种水果,最终得到应制作何种餐品的决策。

这个练习展示了“函数即服务”(FaaS)和“无服务器编排”的强大之处:你可以用很少的代码,通过组合小型、可重用的组件,来构建灵活、可扩展的自动化流程。这种模式与Linux管道(|)的思想一脉相承,是构建现代数据工程和微服务架构的重要基础。

050:什么是数据湖

在本节课中,我们将要学习数据湖的核心概念,特别是它在AWS环境中的具体实现和作用。我们将探讨数据湖如何存储和处理数据,以及它为何能支持多种数据工作负载。


上一节我们介绍了数据存储的基本概念,本节中我们来看看数据湖的具体架构和优势。

数据湖本质上是一个集中式的存储库,允许你以任意规模存储所有结构化和非结构化数据。在AWS环境中,这通常通过S3对象存储服务来实现。

S3是一个对象存储系统,它提供了极高的并发访问能力,本质上是无限或接近无限的并发处理能力与计算资源。这样设计的目的是让你能够同时执行多项任务。

以下是数据湖支持的核心功能:

  • 处理多种数据类型:数据湖能够同时处理结构化数据(如键值对存储格式)和非结构化数据(如原始文本)。
  • 进行分析工作:AWS内部提供了如Athena这样的工具,允许你直接对非结构化数据进行查询并生成报告。
  • 进行机器学习:可以利用近乎无限的磁盘存储空间来存储模型、对模型进行版本控制,甚至提取训练数据,并最终将新创建的模型存回S3系统。
  • 同步本地系统:例如,如果你在专用数据中心拥有一个大型GPU集群,你可以在本地和云端之间同步数据,在本地训练模型,然后将模型和训练数据推回S3进行快照备份。
  • 支持实时处理:这是使用数据湖的一个巨大优势,能够处理实时数据流。

因为数据能够利用这种近乎无限的处理能力进行处理,所以你无需将数据四处移动。这对于在其之上构建新的托管服务是一个巨大的优势。像AWS SageMaker或AWS Athena查询系统这样的服务能够构建在数据湖之上,正是得益于数据无需移动的特性。

最后,数据湖还必须是一个低成本的存储系统。所有这些特点结合起来,共同构成了数据湖的价值主张。


本节课中我们一起学习了数据湖的定义及其在AWS环境中的关键特性。我们了解到,数据湖的核心优势在于其能够以低成本、高并发的形式集中存储各类数据,并允许在其上直接进行分析、机器学习和实时处理,而无需频繁移动数据,从而为构建上层数据服务提供了强大的基础。

051:数据仓库与特征存储对比

在本节课中,我们将要学习数据仓库与特征存储这两种数据管理技术的核心区别。我们将通过对比它们的架构、用途和适用场景,帮助你理解在数据工程中如何选择合适的技术。

概述

数据仓库和特征存储是现代数据架构中处理和管理数据的两种关键技术。它们服务于不同的目的和用户群体。理解它们的差异对于构建高效的数据管道至关重要。

数据湖:数据的起点

上一节我们介绍了数据管理的基本概念,本节中我们来看看具体的技术。一切始于数据湖

数据湖是云计算环境提供的一种存储方案,它本质上能提供近乎无限的存储空间和磁盘容量。数据湖能够接收两种类型的数据:

  • 批处理数据:例如一次性上传数TB的历史数据。
  • 流式数据:例如实时更新的股票行情信息。

数据湖中的数据通常是原始的、未经过格式化的,因此被认为是较低质量的数据。

数据仓库:服务于商业智能

数据仓库从数据湖中提取数据,并执行提取、转换和加载操作,这个过程通常被称为 ETL

经过ETL处理后,数据质量得到提升,变得结构化且易于分析。数据仓库的主要服务对象是商业智能领域。

以下是数据仓库的典型应用场景:

  • 生成报告
  • 构建仪表盘
  • 进行商业智能分析

这些通常是以定时任务的形式运行,为公司的高管和业务领导者生成所需的报告。

特征存储:服务于机器学习

然而,随着技术发展,出现了一个新的标准——特征存储

特征存储与数据仓库不同,它的核心目标是创建可复用的、高质量的机器学习输入特征。它的最终用户是训练系统,即后续将要使用这些特征的机器学习系统。

由于特征以易于复用的方式存储,在使用前通常不需要大量的准备工作。之后,我们可以利用这些特征:

  • 进行预测
  • 创建连接到特征存储的客户端应用

特征存储更侧重于人工智能和机器学习领域。

核心对比与总结

在本节课中,我们一起学习了数据仓库与特征存储的对比。

总而言之,数据仓库和特征存储都是数据管道中非常有价值的组成部分。在现实应用中:

  • 数据仓库更偏向于商业智能
  • 特征存储更偏向于机器学习工作空间。

同时,我们了解到从数据湖(原始、低质量数据)到数据仓库或特征存储(高质量、结构化数据),是一个数据价值不断提升的过程。

052:大数据挑战

概述

在本节课中,我们将要学习大数据领域面临的几个核心挑战。我们将通过“3V”模型来理解大数据的定义,并探讨数据量、数据速度和数据多样性如何共同构成了现代数据工程需要解决的关键问题。


理解大数据的“3V”模型 🎯

思考大数据的一种理想方式是“3V”概念,即数据量数据多样性数据处理速度

这个模型为我们提供了一个框架,用以界定和分类大数据问题。


挑战一:数据量 📊

上一节我们介绍了“3V”模型,本节中我们来看看第一个“V”——数据量。

数据量指数据的巨大规模。这可以是太字节级的数据,甚至是拍字节级的数据。定义大数据问题的一种方式,就是处理海量的数据。

以下是数据量挑战的典型例子:

  • 太字节级的数据
  • 拍字节级的数据

挑战二:数据处理速度 ⚡

了解了数据量的挑战后,我们接下来关注第二个“V”——数据处理速度。

速度是定义大数据问题的另一种方式。这指的是系统需要处理极高频率的数据流入或请求。

以下是速度挑战的典型场景:

  • 每秒一万次请求
  • 每秒十万次请求
  • 每秒一百万次请求

这些规模通常出现在社交媒体网络或股票流数据服务等场景中。


挑战三:数据多样性 🎭

最后,我们来看看“3V”中的最后一个挑战——数据多样性。

数据多样性是大数据的另一个挑战。数据可能是CSV文件、SQL文件、二进制文件或视频文件。数据也可能是大数据领域本身的特定格式。数据的多样性带来了挑战,使得我们需要专门的大数据系统来处理这种庞大的、异构的数据集合。


总结

本节课中我们一起学习了定义大数据的“3V”模型。我们探讨了数据量带来的规模挑战,数据处理速度对系统实时性的要求,以及数据多样性所涉及的格式与类型复杂性。理解这三个维度是设计和构建有效大数据解决方案的基础。

053:大数据处理类型

🎯 概述

在本节课中,我们将学习大数据处理的三种主要类型。理解这些分类有助于我们在设计数据系统时,无论是大型还是小型系统,都能选择合适的方法和工具。

📊 描述性大数据处理

上一节我们了解了大数据处理的整体框架,本节中我们首先来看看描述性大数据处理。

描述性大数据处理是一种面向历史数据的处理方式。它通常表现为仪表盘或传统的报告形式,数据流向数据仓库。我们可以将其理解为对已发生事件的总结和呈现。

以下是描述性数据处理的核心特点:

  • 处理对象是历史数据
  • 输出形式是描述已发生事件的报告或仪表盘
  • 典型应用场景是数据仓库中的传统商业智能分析。

⚡ 实时大数据处理

了解了面向过去的描述性处理,本节我们来看看面向当下的实时大数据处理。

实时数据处理具有独特性,它处理来自实时系统(如Kinesis或Spark)的数据流。例如,这可能是广告数据或来自社交网络的流数据。此时,数据正在动态变化,我们尚不完全清楚其中正在发生什么,事件(如新出现的标签)会持续改变数据状态。因此,处理这类数据需要不同的工具和技术。

以下是实时数据处理的关键点:

  • 数据源是实时数据流,例如来自Kinesis或Spark Streaming。
  • 数据状态动态变化,响应即时事件。
  • 处理目标是理解并响应正在发生的事件。

🔮 预测性大数据处理

前面我们讨论了处理过去和当前数据的方法,最后,我们探讨面向未来的预测性大数据处理。

预测性数据处理涉及使用数据来预测未来可能发生的情况。这包括诸如预测库存需求、检测欺诈行为(例如,同一张信用卡在多个州同时使用)等任务。这类问题通常属于机器学习和深度学习的范畴。其核心是计算未来某个事件发生的概率

预测性处理可以概括为以下公式:
P(未来事件 | 历史及当前数据)
其中,P 代表概率,我们基于已有的历史数据和实时数据来预测未来事件发生的可能性。

📝 总结

本节课中,我们一起学习了大数据处理的三种基本类型:描述性(历史)、实时性(当下)和预测性(未来)。这种分类框架是思考数据系统设计时的有效方式,无论系统规模大小。理解数据的时间属性——是过去、现在还是未来——是选择正确处理策略和工具的关键第一步。

054:真实世界数据工程管道 🚀

在本节课中,我们将一起学习一个真实世界数据工程管道的构成,了解从本地小规模数据处理到云端大规模系统处理的演变过程,并认识其中涉及的核心工具与概念。

概述

许多时候,当你使用 Jupyter Notebook 和 Pandas 处理小型数据集时,你会将数据加载到本地笔记本电脑,读入一个 DataFrame 并进行处理。

然而,在现实世界中,一旦超出那个非常小的数据样本范围,处理工作往往会变得繁重。因此,你必须使用更强大、更专业的工具来处理这些数据。

从本地到云端的转变

上一节我们提到了本地处理的局限性,本节中我们来看看如何转向更强大的系统。例如,你可能需要一个能够使用 Pandas API 处理数据的大规模系统,有多种技术可以实现这一点。或者,你也可以将数据迁移到像 DynamoDB 或 MongoDB 这样的大规模系统,甚至是图数据库中。

因此,第一步是将数据并行同步到数据湖系统中。例如,你可以将成千上万的文件复制到 Amazon S3,因为只有那里才能处理如此庞大的数据量。

构建云端处理流程

在数据进入云端存储后,下一步是构建处理流程。你可以继续将其与某种基于云的系统同步,例如使用 AWS Lambda 的无服务器功能。

以下是随后可能进行的处理类型:

  • 商业智能类处理:进行数据聚合、报表生成等分析。
  • 人工智能类 API 处理:例如,调用情感分析 API 对文本数据进行处理。

处理完成后,你会将结果数据写回 DynamoDB 这样的数据库系统中。

两种世界的对比

综上所述,我们面对的是两个不同的世界。一方面,我们有本地计算机,它适用于爱好者或实验性的工作流程。

但另一方面,当你进入真实世界的数据管道时,你必须使用不同的工具。因为云技术本身具备扩展到数千、数万甚至数百万并发操作的能力,而这里确实是你能处理某些特定数据工程问题的唯一场所。

总结

本节课中,我们一起学习了真实世界数据工程管道的核心思想:从适合小规模、探索性分析的本地环境(Jupyter Notebook + Pandas),过渡到能够处理海量数据、需要利用云端可扩展服务(如 S3, Lambda, DynamoDB)的工业化流水线。理解这两种模式的差异和适用场景,是构建有效数据解决方案的关键。

055:数据反馈循环 🔄

在本节课中,我们将要学习现代企业中一个核心概念——数据反馈循环。我们将了解数据如何从用户产生,经过一系列处理,最终转化为智能产品或服务,并形成一个持续循环的过程。


上一节我们介绍了数据工程的基本范畴,本节中我们来看看数据在企业中是如何流动并创造价值的。数据反馈循环描述了数据从产生到最终应用的完整闭环。

典型的现代公司数据反馈循环始于用户,他们是数据的创造者。

这些数据随后被汇集到更大的数据池中。

接着,数据被处理并存入更庞大的数据系统,例如特征存储。

然后,这些数据被用于人工智能机器学习深度学习等领域。

最终,这些技术被转化为产品。例如,能够通过AI生成图像的工具,或是能够总结海量数据的自然语言处理工具。

因此,数据反馈循环实质上是一个持续不断的过程

MLOps(机器学习运维)或相关的方法论,正是致力于解决如何让这些数据反馈循环更高效,以及如何为组织增加投资回报率


以下是构成数据反馈循环的关键步骤列表:

  1. 数据生成:用户与系统交互,产生原始数据。
  2. 数据汇集:原始数据被收集并整合到中央数据池中。
  3. 数据处理:数据经过清洗、转换,并存储于特征库等专用系统。
  4. 模型开发:利用处理后的数据训练AI/ML模型。
  5. 产品集成:将训练好的模型部署到实际应用中,形成产品功能。
  6. 价值创造与反馈:产品服务用户,同时产生新的数据,循环再次开始。

本节课中我们一起学习了数据反馈循环的概念。我们看到了数据如何从用户端出发,经过收集、处理、分析并最终赋能AI产品,而产品的使用又会生成新的数据,从而形成一个自我强化的闭环。理解这一循环是构建高效、有价值的数据管道和AI系统的基石。

056:虚拟化技术 🖥️

在本节课中,我们将学习计算机虚拟化技术。我们将介绍什么是计算机虚拟化,以及它在应用部署、应用扩展和硬件利用率方面的优势。

什么是计算机虚拟化?

上一节我们介绍了课程目标,本节中我们来看看虚拟化的核心概念。

硬件虚拟化涉及在实际硬件和运行在其上的应用程序之间创建一个抽象层。对于应用程序而言,这个层看起来就像一台拥有完整操作系统的独立计算机。

虚拟化的优势

了解了虚拟化的基本概念后,本节我们将探讨它的主要优势。虚拟化的优势包括可靠的部署、灵活的扩展以及高效的硬件利用率。

1. 可靠的部署

软件通常需要部署到多个环境中。在简单情况下,可能只有一个开发环境和一个生产环境。在大型项目中,通常还会有质量控制、安全测试、性能测试以及预发布(staging)环境。

当我们开发软件时,会编写代码、确定外部依赖(如软件包)并设置环境或配置(如环境变量或配置文件)。在不同环境间部署时,一个挑战是确保所有这些元素都能被准确复制。

例如,如果一个软件包的版本发生变化,代码的行为也可能随之改变。如果我们部署的代码期望某个特定版本的包,而环境中是另一个版本,代码就可能无法运行。

有多种方法可以解决这个问题,从详细记录的运行手册,到使用基础设施即代码(IaC)工具,如 Chef、Ansible 和 Terraform。而通过虚拟化技术,我们可以将特定版本的代码、依赖项和配置打包在一起,作为一个单元进行部署。这保证了我们在开发和测试环境中测试的版本,与后续部署环境中的版本完全一致。

2. 灵活的扩展

3. 高效的硬件利用率


本节课中,我们一起学习了计算机虚拟化的基本概念。我们了解到,虚拟化通过在硬件和软件之间创建抽象层,带来了可靠的部署、灵活的扩展和更高的硬件利用率等核心优势。这为后续学习容器化等技术奠定了重要基础。

057:应用扩展 🚀

在本节课中,我们将学习应用扩展的基本概念,了解从传统物理服务器部署到现代虚拟化部署的演进过程,以及这种演进如何帮助我们更高效地管理计算资源。

传统部署的挑战

上一节我们介绍了应用部署的基本背景,本节中我们来看看传统部署方式面临的挑战。

当我们将一个应用程序部署到物理服务器上时,服务器必须配备足以支撑该应用在最大负载下运行所需的全部资源。

如果随着时间的推移,应用程序需要更多资源,那么我们就需要将其重新部署到一台更大型或性能更强的服务器上。这个过程通常会导致应用程序停机,并且需要相当多的工作量。

如果应用程序的使用量随时间波动,例如白天使用量大而夜间使用量小,我们仍然需要根据其峰值负载来配置服务器。这意味着在相当长的一段时间内,该服务器的资源可能未被充分利用。

虚拟化带来的解决方案

了解了传统部署的局限性后,本节我们来看看虚拟化技术如何提供解决方案。

当我们使用虚拟化技术时,我们可以在一个服务器上运行应用程序。同时,我们也可以在另一个服务器上,或者在同一个服务器上运行该应用的多个副本。

这意味着我们可以根据负载需求进行横向扩展,也可以在负载下降时进行横向收缩。当此应用程序需求较低时,我们可以将服务器资源用于其他应用程序的需求。

核心概念总结

以下是本节课的核心概念总结:

  • 纵向扩展:通过升级单个服务器的硬件(如CPU、内存)来应对增长的需求。这通常涉及停机。
  • 横向扩展:通过增加更多服务器实例(或容器)来分散负载。这可以在不中断服务的情况下进行。
  • 资源利用率:虚拟化允许更动态地分配资源,从而提高整体基础设施的效率,避免为应对峰值负载而长期过度配置资源。

本节课中,我们一起学习了应用扩展从静态的物理服务器部署到动态的虚拟化部署的演进。我们理解了纵向扩展的局限性和横向扩展的灵活性,以及虚拟化如何帮助我们根据实际需求弹性地调整资源,最终实现更高的资源利用率和更敏捷的运维能力。

058:硬件利用率

在本节课中,我们将探讨虚拟化技术如何帮助我们更高效地利用硬件资源。我们将了解通过在同一台物理服务器上运行多个应用实例,如何实现资源的动态分配与最大化利用。


上一节我们介绍了虚拟化带来的部署一致性和弹性伸缩能力。本节中,我们来看看虚拟化如何提升硬件的整体利用率。

虚拟化的核心优势之一是允许我们在单台服务器上运行应用的多个副本。这意味着,当一个应用的需求较低时,其占用的资源可以被释放出来,供其他应用使用。

以下是实现硬件高效利用的几个关键点:

  • 动态资源分配:当某个应用程序的资源需求较低时,系统可以自动减少分配给它的资源(如CPU、内存)。
  • 多应用共存:被释放出来的资源可以立即分配给同一台服务器上其他需要资源的应用程序。
  • 按需启停:通过快速启动(spin up)和关闭(spin down)不同的应用程序,硬件资源得以在不同工作负载间灵活切换。

这个过程可以抽象为以下逻辑:

if application.demand < threshold:
    free_up_resources(application)
    allocate_resources(other_application)

通过上述机制,我们能够确保硬件资源很少处于闲置状态,从而实现了对硬件投资的最大化利用。


本节课中我们一起学习了虚拟化技术提升硬件利用率的核心原理。总结来说,虚拟化通过实现部署一致性、支持弹性伸缩,并允许在同一硬件上动态调度多个应用,使我们能够充分利用硬件资源,避免浪费。

059:虚拟机简介 🖥️

在本节课中,我们将要学习虚拟机的核心概念。我们将了解什么是虚拟机、什么是管理程序(Hypervisor)、如何创建虚拟机以及如何在虚拟机上安装操作系统。


什么是虚拟机?

虚拟机是一种软件模拟的完整计算机系统。它模拟了包括硬件和操作系统在内的完整机器环境。

目前广泛使用的两种机器虚拟化技术是虚拟机容器。两者都将应用程序与其依赖项打包在一起,但区别在于它们模拟真实计算机的程度不同。

虚拟机模拟了一台完整的机器,包括硬件和操作系统。因为每个虚拟机都有自己的操作系统,所以我们可以在同一台物理主机上运行具有不同操作系统的虚拟机。

一些流行的虚拟机解决方案包括:

  • Microsoft Hyper-V
  • VMware Fusion
  • Oracle VirtualBox
  • Citrix Hypervisor

什么是管理程序(Hypervisor)?

上一节我们介绍了虚拟机,本节中我们来看看支撑虚拟机的关键组件——管理程序。

管理程序是位于物理主机和虚拟机之间的虚拟化层。一个单一的管理程序可以运行多个虚拟机。

管理程序主要分为两种类型:

  • 类型一:这种类型更常用于服务器环境,它被设计为直接安装在硬件之上,因此无需与主机操作系统共享任何资源。
  • 类型二:这种类型通常用于个人工作站,它安装在主机操作系统之上运行。

如何创建与安装系统?

了解了虚拟机和管理程序的基础后,接下来我们看看如何实际操作。

以下是创建虚拟机并安装操作系统的一般步骤:

  1. 选择并安装管理程序:首先,根据你的需求(如个人使用或服务器部署)选择并安装一款管理程序软件,例如 VirtualBox 或 VMware。
  2. 创建新虚拟机:在管理程序中,启动“新建虚拟机”向导。你需要为虚拟机分配计算资源,例如 CPU 核心数、内存大小和硬盘空间。
  3. 配置虚拟硬件:在向导中,配置虚拟机的硬件设置,包括网络适配器、显示设置等。
  4. 安装操作系统:将操作系统的安装镜像(如 ISO 文件)挂载到虚拟机的虚拟光驱中,然后启动虚拟机。虚拟机会从该镜像引导,并开始操作系统的安装过程,其步骤与在物理机上安装完全相同。

总结

本节课中我们一起学习了虚拟化的基础知识。我们明确了虚拟机是模拟完整硬件的软件计算机,而管理程序是实现虚拟化的核心软件层。我们还了解了创建虚拟机并安装操作系统的基本流程。掌握这些概念是后续在虚拟化环境中部署和运行数据工程应用的重要基础。

060:使用VirtualBox创建虚拟机 🖥️

在本节课中,我们将学习如何使用VirtualBox创建一台虚拟机,并在其上安装Linux Mint操作系统。我们将从下载软件开始,逐步完成虚拟机的配置、操作系统的安装,并了解快照等实用功能。

概述

虚拟化技术允许我们在单一物理主机上运行多个独立的操作系统实例。本节教程将指导你使用VirtualBox这一流行的虚拟机管理程序(Hypervisor),创建并配置一个Linux Mint虚拟机。我们将涵盖从软件下载、虚拟机创建、系统安装到基本管理的完整流程。


创建虚拟机

首先,我们需要下载并安装虚拟机管理程序。我们将使用VirtualBox作为我们的Hypervisor。

  1. 从VirtualBox官方网站下载并安装VirtualBox。
  2. 由于虚拟机需要一个操作系统,我们从Linux Mint官网下载Linux Mint的安装镜像文件。

完成镜像下载和VirtualBox安装后,即可打开VirtualBox应用程序。

配置虚拟机参数

首次打开VirtualBox,你会看到类似欢迎界面的屏幕。要创建新虚拟机,请点击“新建”按钮。

以下是创建虚拟机时需要配置的关键参数:

  • 名称:为你的虚拟机命名。
  • 文件夹:这是虚拟机文件的存储目录,可以根据需要修改。
  • 类型和版本:选择与将要安装的操作系统匹配的类型和版本。对于Linux Mint,选择类型为“Linux”,版本为“Ubuntu(64-bit)”即可。
  • 内存大小:分配主机内存(RAM)给虚拟机。分配过少会导致虚拟机性能不佳;分配过多则会影响主机效率。建议根据主机配置合理分配。
  • 虚拟硬盘:为虚拟机创建虚拟磁盘。
    • 硬盘文件类型:选择VDI (VirtualBox Disk Image)格式。如果你需要在不同Hypervisor间共享虚拟机,可以选择其他格式。
    • 存储在物理硬盘上:选择动态分配。这意味着虚拟硬盘文件最初很小,随着虚拟机内数据增加而动态增长,直至达到设定的最大容量。另一种固定大小选项会立即占用全部指定容量,性能稍好,但会浪费未使用的空间。
    • 文件位置和大小:设置虚拟硬盘文件的存储位置和最大容量。安装Linux Mint至少需要12GB,建议分配13GB或更多。

完成上述配置后,虚拟机即创建成功,会显示在VirtualBox主界面的左侧列表中。

安装操作系统

双击左侧新建的虚拟机即可启动它。由于虚拟机尚无操作系统,VirtualBox会提示你选择启动盘。

  1. 选择之前下载的Linux Mint安装镜像文件作为启动盘。如果未自动列出,可以点击文件夹图标手动查找。
  2. 启动后,虚拟机将捕获你的键盘和鼠标输入。重要:要释放控制权(将键盘鼠标焦点交还给主机),需要按下Host键(通常是键盘右侧的Ctrl键),你可以在虚拟机窗口底部看到提示。
  3. 虚拟机将从安装镜像启动,进入Linux Mint安装界面。双击桌面上的“Install Linux Mint”图标开始安装。
  4. 安装程序会警告将擦除磁盘并安装Linux。这里所指的“磁盘”是我们的虚拟硬盘,因此可以安全继续。
  5. 按照提示选择时区、创建用户名、计算机名并设置密码。注意:如果勾选“自动登录”,任何能访问此虚拟机的人都可以直接进入系统。对于演示环境可以勾选,但生产环境不建议。
  6. 等待安装完成,然后重启虚拟机。

重启后,你将运行在全新安装的Linux Mint系统中。

虚拟机的关闭与快照

关闭虚拟机窗口时,有三个选项:

  • 关闭电源:相当于强制断电。
  • 正常关机:向虚拟机发送关机信号,让其安全关闭。
  • 保存虚拟机的当前状态:将虚拟机的完整运行状态(包括所有打开的程序和文件)保存下来,下次启动时直接恢复到此状态。

快照功能非常有用,它可以保存虚拟机在某个时间点的完整状态。

  1. 在虚拟机运行时(或关闭后),在VirtualBox管理界面选中该虚拟机,点击“快照”按钮。
  2. 为快照命名并添加描述,然后点击“确定”。
  3. 快照创建后,你可以在虚拟机上进行任何操作,例如安装新软件或删除文件。
  4. 如果操作出现问题,你可以在虚拟机关机状态下,右键点击之前的快照,选择“恢复”,即可将虚拟机回滚到创建快照时的状态。例如,我们可以在桌面上创建一个文件夹,创建快照后将其删除,然后通过恢复快照,文件夹又会重新出现。

这意味着你可以在尝试有风险的操作(如安装新软件、修改系统配置)前创建一个快照,以便随时回退到稳定状态。


总结

本节课我们一起学习了虚拟机的创建与管理。我们使用VirtualBox创建了一台虚拟机,并在其上安装了Linux Mint操作系统。

核心概念总结如下:

  • 虚拟机:模拟了包括硬件和操作系统在内的完整计算机系统。
  • 管理程序(Hypervisor):是运行虚拟机的虚拟化软件层,例如我们使用的VirtualBox
  • 虚拟化的优势:通过虚拟机,我们可以在同一台物理主机上同时运行多种不同的操作系统。

通过掌握虚拟机的创建、配置、系统安装和快照管理,你为后续的数据工程环境搭建打下了坚实的基础。

061:容器概念 🐳

在本节课中,我们将学习另一种虚拟化解决方案——容器。我们将比较容器与虚拟机的异同,介绍通用的容器概念,并重点讲解Docker容器解决方案的特定概念及其架构。

概述

容器是一种将应用程序及其依赖项打包在一起的虚拟化技术。与虚拟机类似,容器也具有环境可移植性,并能在一台主机上同时运行多个实例。然而,它们在架构和资源消耗上存在显著差异。

容器与虚拟机的比较

上一节我们提到了虚拟化,本节中我们来看看容器与虚拟机的核心区别。

容器和虚拟机都能将应用程序及其依赖项捆绑在一起。两者都能在不同环境中移植,并能在同一台主机上并发运行多个实例。

虚拟机运行在位于主机之上的管理程序(Hypervisor)上。每个虚拟机都拥有自己独立的操作系统

容器则运行在位于主机之上的容器引擎上。但与虚拟机管理程序不同,容器引擎本身运行着一个操作系统,而所有在该引擎上运行的容器都共享这个操作系统。

容器的主要特性

正因为上述架构差异,容器具有以下特点:

  • 容器更轻量
  • 容器的启动和停止速度更快

以下是容器与虚拟机的一些关键差异总结:

  • 操作系统:容器共享单个操作系统。
  • 运行限制:由于共享操作系统,同一引擎上只能运行相同操作系统的容器。
  • 生命周期:容器仅在内部有应用程序运行时才存在,因此非常轻量。
  • 内存占用:相比之下,每个虚拟机都有自己的操作系统,会一直运行直到操作系统关闭,因此内存占用更大。

Docker容器架构

现在,让我们深入了解Docker这一特定容器解决方案的架构。

Docker容器架构的核心组件包括:

  • Docker守护进程(Docker Daemon):一个在主机上运行的后台服务,负责管理容器、镜像、网络和存储卷。
  • Docker客户端(Docker Client):用户与Docker守护进程交互的命令行工具。
  • Docker镜像(Docker Images):只读模板,用于创建容器。镜像包含运行应用所需的代码、运行时、库和环境变量。
  • Docker容器(Docker Containers):镜像的运行实例。你可以使用Docker API或CLI来创建、启动、停止、移动或删除容器。
  • Docker注册表(Docker Registry):用于存储Docker镜像的服务,例如Docker Hub。

其基本工作流程可以用以下伪代码描述:

# 用户通过客户端发送命令
docker run <image_name>

# 守护进程执行操作
1. 检查本地是否存在指定镜像
2. 若不存在,则从注册表(如Docker Hub)拉取镜像
3. 基于该镜像创建一个新的可写容器层
4. 分配网络和存储接口
5. 启动容器,运行指定应用

总结

本节课中,我们一起学习了容器的核心概念。我们了解到容器是一种轻量级、快速启动的虚拟化技术,它通过共享主机操作系统的内核来实现高效运行。我们比较了容器与虚拟机的区别,并介绍了Docker容器解决方案的基本架构。理解这些概念是进行现代应用部署和微服务开发的重要基础。

062:Docker简介 🐳

在本节课中,我们将要学习Docker容器的基础知识。Docker既是一个容器平台,也是一家推广该平台的公司,同时它还提供与Docker容器相关的工具。虽然存在其他基于Linux的容器技术,但截至目前,Docker是应用最广泛的容器类型。

Docker概述

Docker使用Go语言编写,并在底层利用Linux命名空间来隔离容器。根据本课程录制时的信息,Docker提供了可运行Linux和Windows的容器。

理解Docker生态系统中的镜像容器这两个核心概念至关重要。

  • 镜像是一个只读的模板,用于创建容器。你可以使用Dockerfile自己创建镜像,也可以使用预先构建好的镜像。
  • 容器是镜像的可运行实例。

需要明确的是,与虚拟机不同,容器本身不存储状态。也就是说,当你关闭一个容器时,它不会保存运行容器的任何状态。当然,你可以将外部存储附加到容器上,从而有效地在那里存储状态,但容器本身不会存储。

Docker桌面应用

Docker Desktop是一个用于与Docker交互的流行应用程序,可在OSX、Windows和Linux系统上运行。在Docker Desktop应用程序中,捆绑了以下组件:

  • Docker Daemon:Docker守护进程。
  • Docker Client:Docker客户端。
  • Docker Compose:用于定义和运行多容器Docker应用程序的工具。
  • Kubernetes:一个用于编排和运行Docker容器的系统。

Docker镜像仓库

上一节我们介绍了Docker的基本组件,本节中我们来看看Docker镜像的存储位置——镜像仓库。

Docker镜像仓库是存储Docker镜像的地方,它们可以是本地的,也可以位于云端。你可以选择创建公共或私有的仓库。目前有许多流行的云仓库解决方案,包括:

  • Docker Hub
  • AWS的Elastic Container Registry
  • Google Cloud的Container Registry
  • Azure的Container Registry

让我们具体看看Docker Hub这个镜像仓库。如果我们进入“探索”部分,可以看到一些推荐的镜像。在左侧,我们可以进行筛选,例如筛选由已验证发布者发布的官方镜像,这有助于我们了解镜像的创建者。这里也能看到一些更受欢迎、被推荐的镜像。

请注意,每个镜像都有一系列与之关联的标签。我们也可以切换到“最近更新”视图,查看哪些镜像最近被更新过。我们还可以按操作系统进行筛选,如前所述,Docker容器可以运行在Linux或Windows上,并支持各种架构。

当我们搜索一个镜像时,会看到在命令行中使用的Docker命令,用于将该镜像拉取到本地的Docker客户端。页面还会提供描述、评论、标签以及一些参考信息。如果你需要特定版本的镜像,标签会非常有用,你可以使用这些标签来拉取特定的版本。此外,页面还提供相关文档。

以上就是Docker Hub仓库的基本运作方式。在后续课程中,我们还将学习如何从命令行访问Docker Hub仓库。


本节课中我们一起学习了Docker的核心概念,包括镜像与容器的区别、Docker Desktop的组成以及如何使用Docker Hub镜像仓库来查找和获取镜像。理解这些基础知识是后续进行容器化开发和部署的关键。

063:Docker架构 🐳

在本节课中,我们将要学习Docker的核心架构。理解其工作原理是有效使用Docker的基础。

概述

Docker的架构基于客户端-服务器模型。我们将探讨其核心组件如何协同工作,以管理镜像、容器和网络。

客户端与守护进程

上一节我们介绍了Docker的基本概念,本节中我们来看看其核心的运行架构。

Docker基于一个客户端-守护进程模型。客户端和守护进程可以运行在同一台主机上,也可以配置为本地客户端向远程守护进程发送命令。

通信机制

客户端与守护进程之间的通信完全通过一个REST API进行。守护进程被动地监听API请求,并根据这些请求来管理镜像、容器和网络。

发送命令的方式

客户端是向守护进程发送命令的主要方式,但并非唯一方式。

以下是向Docker守护进程发送命令的几种途径:

  • 使用 docker 客户端 命令行工具。
  • 直接使用 REST API 发送命令。
  • 使用其他基于此API构建的工具。

对于初学者而言,docker客户端是一个很好的起点。

核心概念回顾

在本节课中,我们一起学习了Docker的架构。现在让我们总结一下目前已学的核心概念:

  • 镜像 是用于创建容器的指令模板。
  • 容器 是镜像的一个运行实例。
  • 注册表 用于存储和分发镜像。

理解这些组件及其交互方式,是掌握Docker技术的关键。

064:Docker客户端 🐳

在本节课中,我们将学习Docker客户端。我们将探讨如何使用Docker客户端向Docker引擎发送指令,包括从远程仓库拉取镜像、运行容器、连接到容器的Shell,以及为容器挂载数据卷以实现数据持久化。

Docker客户端与镜像管理 🖼️

首先,我们来了解Docker客户端和镜像。Docker客户端是一个命令行工具,名为 docker

要查看当前连接的Docker引擎(本例中是本地引擎)中可用的镜像,我们使用 docker images 命令。可以看到,我的本地Docker引擎中目前没有任何镜像。

我们可以使用 docker search 命令在Docker仓库中搜索镜像。默认情况下,使用的仓库是Docker Hub,但你也可以通过配置指向其他仓库。

以下,我们搜索名称中包含“Python”的镜像。搜索结果会显示镜像名称、描述、星级以及是否为官方镜像。

我们可以使用过滤器来优化搜索。例如,这里我们添加一个过滤器,要求镜像必须是官方的。我们还可以设置过滤器来限定星级,比如只显示三星以上的高评级镜像。再次搜索“Python”,可以看到结果被限定为三个镜像。

要将镜像拉取到Docker引擎维护的本地仓库中,我们使用 docker pull 命令,后面跟上镜像名称。这里我们将拉取官方的Python镜像。之前我们提到过镜像有标签,请注意,这里我没有指定标签,因此默认使用 latest 标签。要指定标签,可以在镜像名后加上冒号和标签名,例如 python:3.9

现在,再次使用 docker images 命令,可以看到Python镜像已经可用。

容器操作与管理 📦

要查看由引擎管理的、正在运行的容器,我们使用 docker ps 命令。目前没有容器在运行。

要运行一个容器,使用 docker run 命令。这里我们将运行Python镜像。这个镜像会立即停止,因为没有命令让它持续执行。因此,我们需要添加另一个标志 -it,这将为我们的镜像连接一个交互式Shell。

现在,我们的镜像正在运行,并且我们通过Shell连接到了它,可以在其中运行Python命令。

如果我们切换到另一个终端标签页,再次运行 docker ps,就能看到我们正在运行的容器,包括其容器ID、来源镜像、执行命令以及其他信息。

要停止这个容器,我们需要获取其容器ID,然后使用 docker stop 命令。之后,可以看到没有容器在运行。回到原来的Shell,会发现Python Shell已被强制退出,我们回到了自己的Shell中。

总结 📝

本节课中,我们一起学习了如何使用Docker客户端拉取镜像,以及如何使用该镜像运行容器。我们还学习了如何以附加Shell的方式运行容器,以便在容器运行时与其进行交互。

065:创建与管理数据卷

概述

在本节课程中,我们将学习如何在Docker中创建数据卷,并将其附加到容器上。数据卷是Docker中用于持久化存储数据的重要机制,它允许容器在停止或删除后,其内部的数据依然得以保留。我们将通过实际操作演示如何创建卷、将卷挂载到容器,并验证数据的持久性。


创建并运行一个容器

首先,我们启动一个容器并进入其内部的bash shell。

运行以下命令来启动一个容器并附加到它:

docker run -it bash

请注意,我们之前并未拉取这个bash镜像。但docker run命令会自动拉取我们指定的镜像标签,如果未指定标签,则默认拉取latest标签。

现在,我们已进入容器的bash shell环境。可以像在普通bash中一样查看和操作文件。

让我们尝试创建一个文件:

echo "Hello from first run" > testfile.txt
cat testfile.txt

我们已经创建了一个简单的文件。现在,让我们退出这个bash shell:

exit

为容器命名并管理其生命周期

退出后,我们检查Docker,会发现没有正在运行的容器。

如果我们再次运行相同的容器,这次可以添加一个标志来为容器命名:

docker run -it --name my_named_container bash

我们再次进入bash shell。如果查看周围,会发现之前创建的文件testfile.txt已经不存在了。这是因为每次运行新容器时,它都从一个全新的文件系统开始。

如果我们打开另一个终端,并使用docker ps命令查看正在运行的容器,可以看到我们的容器现在有了一个名字my_named_container。这意味着我们可以通过这个名字来引用我们的容器。

例如,如果我们想停止这个容器,可以使用其名称:

docker stop my_named_container

执行后,可以看到容器已停止。


创建数据卷以实现数据持久化

为了使容器创建的数据能够持久保存,我们需要创建并将一个数据卷附加到容器上。

首先,查看当前可用的卷:

docker volume ls

可以看到,我们的本地Docker引擎中尚未创建任何卷。

接下来,创建一个新的数据卷:

docker volume create my_data_volume

再次运行docker volume ls,现在可以看到一个名为my_data_volume的卷已经存在。


将数据卷挂载到容器

现在,让我们运行一个容器,并将刚创建的卷挂载到它里面。

我们使用-v标志来附加卷到容器。该标志的参数结构为:[卷名]:[容器内的挂载路径]

docker run -it -v my_data_volume:/mounted_volume --name vol_container bash

我们再次使用-it标志以交互模式附加到容器。进入容器后,可以在/mounted_volume目录下看到挂载的卷。

让我们在该卷中创建一个文件:

cd /mounted_volume
echo "Hello from persisted volume" > persistent_file.txt
cat persistent_file.txt

文件内容显示为“Hello from persisted volume”。现在,退出这个容器:

exit

验证数据的持久性

然后,我们再次运行一个容器,挂载同一个数据卷,并使用相同的bash镜像:

docker run -it -v my_data_volume:/mounted_volume bash

进入容器后,查看挂载的卷目录:

ls /mounted_volume
cat /mounted_volume/persistent_file.txt

可以看到,我们之前创建的persistent_file.txt文件依然存在,并且内容保持不变。如果没有挂载卷,这个文件是不会被保留的。


检查容器的挂载信息

我们还可以检查正在运行的容器,查看其挂载的详细信息。

首先,获取容器的ID或名称,然后使用inspect命令:

# 假设容器名为 vol_container, 如果已停止,可以先启动或使用最近运行的容器ID
docker inspect vol_container | grep -A 10 Mounts

在输出结果中,搜索Mounts部分,可以看到我们的卷my_data_volume的挂载信息,包括卷名和它在容器内的目标路径(/mounted_volume)。


总结

在本节课中,我们一起学习了Docker数据卷的核心操作。我们首先创建并运行了一个容器,然后通过为容器命名来更好地管理它。接着,我们创建了一个数据卷,并将其挂载到容器中,从而实现了容器数据的持久化存储。最后,我们通过再次运行容器并挂载同一卷,验证了数据的持久性,并学习了如何检查容器的卷挂载详情。掌握数据卷的使用,是进行可靠数据工程和容器化应用部署的关键一步。

066:在容器中运行数据库 🐘

在本节课中,我们将学习如何使用Docker容器来运行一个数据库服务。我们将以PostgreSQL为例,演示如何拉取镜像、运行容器、设置环境变量、映射端口、挂载数据卷,并最终连接到容器内的数据库执行操作。这种方法允许你在本地运行数据库,而无需在主机上直接安装它。


上一节我们介绍了Docker的基本概念,本节中我们来看看一个更复杂的例子:在容器中运行数据库。

我们将使用Docker官方的PostgreSQL镜像。首先,我们拉取这个镜像的最新版本。

docker pull postgres

接下来,尝试不带任何参数运行它。

docker run postgres

你会看到运行失败,因为PostgreSQL服务器需要设置密码或允许无安全连接。

现在,让我们再次运行Postgres容器,但这次设置必要的参数。

以下是运行命令:

docker run -d \
  --name my-postgres \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -e POSTGRES_USER=myuser \
  -p 5432:5432 \
  -v my-pg-data:/var/lib/postgresql/data \
  postgres

让我们分解这个命令:

  • -d:以后台守护进程模式运行容器。
  • --name my-postgres:为容器指定一个名称。
  • -e POSTGRES_PASSWORD=mysecretpassword:设置环境变量,定义数据库的密码。
  • -e POSTGRES_USER=myuser:设置环境变量,定义数据库的用户名。
  • -p 5432:5432:将容器内部的5432端口映射到主机的5432端口。
  • -v my-pg-data:/var/lib/postgresql/data:将名为my-pg-data的数据卷挂载到容器内的PostgreSQL数据目录。即使容器被删除,数据也会保留在卷中。

现在,我们的容器已经在后台运行。我们可以使用以下命令查看运行中的容器:

docker ps

要连接到这个正在运行的容器内部,我们使用docker exec命令。

以下是连接命令:

docker exec -it my-postgres bash

这个命令会在名为my-postgres的容器内启动一个交互式bash shell。

进入容器后,我们可以使用psql客户端连接到PostgreSQL服务器。

psql -h localhost -p 5432 -U myuser

现在,我们已经成功连接到了运行在容器内的PostgreSQL服务器。可以看到当前没有表。

我们可以在此执行SQL命令。例如,创建一个名为test_table的表,它有一个name列。

CREATE TABLE test_table (name VARCHAR(255));
INSERT INTO test_table VALUES ('Hello from Docker');
SELECT * FROM test_table;

执行后,可以看到SQL命令生效,表已创建并插入了数据。输入\q退出psql,再输入exit退出容器的bash shell。

容器仍在后台运行。最后,我们可以查看一下本地创建的数据卷。

docker volume ls

在列出的卷中,只有my-pg-data是我们显式创建的。其他卷是在运行各种容器过程中自动创建的。


本节课中我们一起学习了如何在本地通过Docker运行数据库,而无需在机器上直接安装。我们连接了数据卷以确保数据持久化,并通过shell连接到容器来对其运行SQL。

让我们回顾一下本课引入的一些Docker命令:

  • docker pull:从远程仓库拉取镜像。
  • docker images:列出本地已有的镜像。
  • docker ps:显示正在运行的容器。
  • docker run:从镜像运行一个容器。
  • docker volume:用于创建卷或列出本地可用的卷。

067:构建Docker镜像 🐳

在本节课中,我们将学习如何构建一个Docker镜像。我们将重点介绍最常用的构建命令 docker build,并深入理解其核心组成部分——Dockerfile。通过具体的示例,你将掌握从零开始创建自定义镜像的完整流程。

概述

Docker镜像是容器运行的基础。docker build 是构建镜像最常用的方式,它通过读取一个名为 Dockerfile 的文本文件,并配合一个构建上下文(context)来生成镜像。虽然镜像也可以从正在运行的容器创建,但使用 Dockerfile 进行构建是更标准化和可复现的方法。

Docker Build 命令详解

上一节我们介绍了构建镜像的基本概念,本节中我们来看看具体的构建命令 docker build

docker build 命令使用一个 Dockerfile 和一个构建上下文来创建 Docker 镜像。Dockerfile 是一个包含用于构建镜像的指令的文件。默认情况下,Docker 期望该文件名为 Dockerfile,但也可以使用其他文件名,并通过 -f 标志在构建时指定。

构建上下文是构建过程中要包含的文件所在的位置。这个位置通常是一个本地目录,但也可以是一个远程目录的URL,例如 GitHub 或 GitLab 上的项目。

以下是 docker build 命令的基本结构:

docker build [OPTIONS] PATH | URL | -

其中,PATH | URL | - 是必需的参数,指向构建上下文。

构建上下文与 .dockerignore 文件

在构建镜像时,理解构建上下文至关重要。对于远程 Docker 引擎,上下文中的所有文件都会被推送到引擎,因此最好只在上下文中包含构建所必需的文件和目录。

如果你有文件在上下文中但不希望被包含在构建中,可以使用 .dockerignore 文件。通过 .dockerignore 文件,我们可以指定构建过程中要忽略的特定文件或路径。

实战:构建第一个镜像

现在,让我们动手构建一个镜像。假设我们位于一个包含 Dockerfile 的目录中。

因为 Dockerfile 使用了默认名称且位于上下文中,我们无需通过 -f 指定文件路径,只需提供上下文路径即可。执行以下命令:

docker build .

命令执行后,我们可以通过 docker images 查看镜像列表,确认新镜像已创建。请注意这里会报告镜像ID,以便你在镜像列表中识别它。

为镜像添加标签

接下来,我们再次构建镜像,但这次为其添加一个标签。-t--tag 标志允许我们为镜像创建一个名称。

标签的格式通常为 名称:标签。冒号后的标签是可选的,可以是版本号或环境标识(如 latest)。latest 标签常用于表示最新的构建,虽然实际的“最新”镜像可能会更新,但始终可以通过该标签获取。

执行带标签的构建命令:

docker build -t my-image:latest .

现在,再次运行 docker images,可以看到我们的镜像拥有了名称和标签。这个镜像现在就可以被用来运行容器了。

总结

本节课中我们一起学习了 Docker 镜像构建的核心知识。我们了解了 docker build 命令的用法,认识了 Dockerfile 和构建上下文的作用,并实践了如何构建一个基础镜像以及为其添加有意义的标签。掌握这些是进行高效、可复现应用部署的基础。

068:Dockerfile详解 🐳

在本节课中,我们将深入学习Dockerfile。Dockerfile是构建Docker镜像的核心配置文件,它包含了一系列指令,用于定义如何从基础镜像开始,逐步构建出我们最终需要的应用镜像。理解这些指令是掌握Docker容器化技术的关键一步。

Dockerfile基础

上一节我们介绍了Docker的基本概念,本节中我们来看看Dockerfile的具体构成和作用。

Dockerfile通常被命名为 Dockerfile。通过使用 docker build 命令的 -f 标志,可以指定不在当前上下文目录中,或者不遵循默认命名规则的Dockerfile文件。

Dockerfile的主要目的是包含一系列由 docker build 命令使用的构建指令。

常用Dockerfile指令

以下是Dockerfile中最常用的一些核心指令及其功能。

  • FROM:此指令用于指定构建过程所基于的父镜像。镜像通常是分层构建的,FROM 指令定义了起点。它通常是Dockerfile中的第一条指令。

    • 示例FROM python:3.9-slim
  • COPY:此指令用于将文件从构建上下文(通常是Dockerfile所在的目录)复制到正在构建的镜像中。如果你的应用代码、配置文件或其他资源需要包含在镜像内以供正常运行,就需要使用 COPY 指令。

    • 示例COPY ./app /usr/src/app
  • WORKDIR:此指令用于为后续的 RUNCMDENTRYPOINTCOPYADD 指令设置工作目录。与在 RUN 指令中执行 cd 命令相比,使用 WORKDIR 是更清晰、更推荐的做法。

    • 示例WORKDIR /usr/src/app
  • RUN:此指令用于在构建镜像的过程中执行命令。通常用于安装软件包、编译代码或执行其他构建步骤。

    • 示例RUN pip install --no-cache-dir -r requirements.txt
  • ENTRYPOINT:此指令用于配置容器启动时运行的主命令或可执行文件。由 ENTRYPOINT 定义的命令决定了基于此镜像运行的容器的生命周期。

    • 示例ENTRYPOINT [“python”, “app.py”]
  • ENV:此指令用于设置环境变量。这些变量在镜像构建时被设置,并且在基于此镜像运行的容器内部持续可用。

    • 示例ENV FLASK_APP=app.py

总结

本节课中我们一起学习了Dockerfile的核心指令。我们了解到,FROM 定义了基础镜像,COPY 用于添加文件,WORKDIR 设置工作目录,RUN 执行构建命令,ENTRYPOINT 指定容器主进程,而 ENV 则用于配置环境变量。掌握这些指令是编写高效、可维护的Dockerfile,从而成功容器化应用的基础。

069:Dockerfile示例 🐳

在本节课中,我们将通过两个具体的例子来学习如何编写Dockerfile,并了解如何构建和运行Docker镜像。


一个简单的Dockerfile示例

首先,我们来看一个非常简单的Dockerfile例子。

这个Dockerfile只包含两条指令。

  • FROM 指令:指定了基础镜像及其标签。
  • ENTRYPOINT 指令:指定了容器启动时运行的主可执行文件,在本例中是命令行命令 echo

以下是该Dockerfile的内容:

FROM ubuntu:latest
ENTRYPOINT ["echo", "Hello Docker"]

现在,我们来构建并运行这个镜像。可以看到,构建后生成了一个名为 hello 的镜像。当我们运行这个镜像时,它会执行 echo 命令,输出“Hello Docker”。命令执行完毕后,容器就会停止。


一个更复杂的Dockerfile示例

上一节我们介绍了一个基础示例,本节中我们来看看一个更贴近实际应用的例子。

在这个目录中,我们有一个Dockerfile和一个Python文件。我们先看一下Python文件的内容。

这是一个非常简单的Flask应用。它设置了一个端点,该端点会返回一个字符串“hello”,后面跟着一个从环境变量中获取的名字。应用运行在端口 8080 上。

以下是Python文件 app.py 的内容:

from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def hello():
    name = os.environ.get('NAME', 'World')
    return f'Hello {name}!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

接下来,我们查看对应的Dockerfile。它同样以 FROM 指令开始,指定了基础镜像为 python:3.12-slim

以下是该Dockerfile的完整内容:

FROM python:3.12-slim
COPY . /app
WORKDIR /app
RUN pip install flask
ENV NAME=Henri
ENTRYPOINT ["python", "app.py"]

以下是构建此镜像所涉及的步骤列表:

  • COPY . /app:将构建上下文中的所有文件复制到镜像内的 /app 目录。
  • WORKDIR /app:将镜像内的工作目录设置为 /app
  • RUN pip install flask:运行命令,安装此代码所需的依赖(Flask)。
  • ENV NAME=Henri:定义一个名为 NAME 的环境变量,并将其值设置为 Henri
  • ENTRYPOINT [“python”, “app.py”]:指定容器启动时运行 python app.py 命令。

现在,我们来构建这个镜像。构建完成后,可以在镜像仓库中看到它。接着,我们运行这个镜像,并将宿主机的端口 80 映射到容器内的端口 8080

此时,如果我们打开一个网页浏览器并访问相应地址,就能看到从运行在Docker容器中的Flask应用返回的消息了。


总结

本节课中,我们一起学习了Docker镜像构建的核心知识。

我们了解到,镜像通常使用 docker build 命令构建。该命令会使用一个构建上下文和一个 Dockerfile 文件。而Dockerfile文件则包含了构建镜像所需的所有指令。通过两个由浅入深的例子,我们实践了如何编写Dockerfile、构建镜像以及运行容器。

070:使用Docker-Compose编排 🐳

在本节课中,我们将要学习如何使用Docker-Compose进行容器编排。我们将了解Compose文件的结构,介绍Airflow平台,并最终使用Docker-Compose在本地运行Airflow。

编排与Docker-Compose简介

上一节我们介绍了Docker容器的基础概念。本节中我们来看看如何管理多个相互关联的容器。

在使用Docker容器时,每个容器通常应代表一个单一的功能或服务。在传统的服务器设置中,我们可能将Web应用和数据库部署在同一台服务器上。但在Docker生态系统中,Web应用和数据库应各自拥有独立的容器。每个容器都有定义其执行方式的主要目的。

例如,一个应用可能包含Web前端、后端数据库、API服务以及缓存层。每个部分都需要运行在自己的容器中。这些容器之间需要定义网络通信,并且它们彼此存在依赖关系。如果API容器没有启动并运行,Web前端将无法正常工作;同样,如果数据库容器没有启动,API容器也无法运行。

为了定义这些多容器应用、它们之间的通信和依赖关系,我们使用一种称为编排工具的技术。Docker-Compose就是这样一种编排工具。它是Docker Desktop附带的另一个Docker客户端,作为创建和管理多容器应用的编排工具。它通过一个称为Compose文件的YAML格式文件来定义编排规则。

Compose文件结构

上一节我们介绍了编排的概念,本节中我们来看看Compose文件的具体结构。

Compose文件包含多个可能的配置部分,其中最主要的是服务(services)部分。每个服务代表一个或多个正在运行的容器实例。文件中还可以定义服务之间或服务与外部之间的网络通信部分,以及可以被Compose文件中其他元素共享的持久化卷存储和配置。

以下是Compose文件中可能包含的主要部分:

  • 服务(Services):定义每个容器的配置,如镜像、端口、卷和环境变量。
  • 网络(Networks):定义容器之间的网络连接方式。
  • 卷(Volumes):定义持久化数据存储。
  • 配置(Configs):定义可被多个服务共享的配置文件。

一个简单的Compose文件示例

让我们来看一个简单的例子。在这个Compose文件中,我们定义了一个名为my-api的单一服务。

version: '3.8'
services:
  my-api:
    image: my-api-image:latest
    ports:
      - "8080:80"
    volumes:
      - ./app:/usr/src/app
    environment:
      - MODE=production

我们为该服务定义了一个源镜像、一个端口映射、一个要挂载的卷,以及一个名为MODE的环境变量。请注意,我们在这里定义的元素,类似于我们使用Docker客户端运行容器时可用的选项。

引入Apache Airflow平台

在了解了Compose文件的基础后,我们将引入一个具体的编排案例:Apache Airflow。

Apache Airflow是一个用于编排复杂工作流的平台。它通常由多个组件构成,例如Web服务器、调度器、执行器以及后端数据库(如PostgreSQL)。由于组件众多,手动使用Docker命令逐个启动和管理这些容器非常繁琐且容易出错。这正是Docker-Compose发挥作用的完美场景。

使用Docker-Compose本地运行Airflow

最后,我们将实践如何使用Docker-Compose在本地运行完整的Airflow服务。

通过一个预先定义好的docker-compose.yaml文件,我们可以使用一条简单的命令docker-compose up来启动Airflow的所有必需服务。Compose文件会确保各个服务(如数据库、Web服务器、调度器)以正确的顺序启动,并配置好它们之间的网络连接和依赖关系。这极大地简化了在开发或测试环境中部署Airflow的流程。


本节课中我们一起学习了Docker-Compose的核心概念。我们了解了为什么需要容器编排,探索了Compose文件的基本结构,并通过一个简单示例加深了理解。最后,我们介绍了Apache Airflow这一多组件应用,并说明了如何使用Docker-Compose来简化其本地部署过程。掌握Docker-Compose是管理复杂微服务架构和数据处理平台(如Airflow)的重要技能。

071:Airflow简介 🌀

在本节课中,我们将要学习Airflow,一个用于管理和编排数据工程工作流的平台。我们将了解其核心概念、基本架构以及如何通过Docker Compose在本地运行它。


什么是Airflow?

Airflow是一个工作流管理平台,专门用于管理被称为工作流的数据工程管道。这些工作流被定义为有向无环图。这些图,以及它们所控制的任务和依赖关系,全部使用Python代码定义。


编写一个简单的DAG

上一节我们介绍了Airflow的核心概念,本节中我们来看看如何用Python定义一个DAG。

以下是一个定义Airflow有向无环图(即DAG)的Python文件示例:

from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from datetime import datetime

# 定义一个简单的Python函数
def my_function(my_argument):
    return f"Hello {my_argument}"

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/20ec6d969bb931fdc3649f35127d3417_3.png)

# 定义DAG
with DAG(
    'my_dag',  # DAG名称
    start_date=datetime(2023, 1, 1),  # 开始日期
    schedule_interval='@daily'  # 调度间隔
) as dag:

    # 使用PythonOperator定义第一个任务
    task1 = PythonOperator(
        task_id='task_1',
        python_callable=my_function,
        op_args=['World']
    )

    # 使用PythonOperator定义第二个任务
    task2 = PythonOperator(
        task_id='task_2',
        python_callable=my_function,
        op_args=['Airflow']
    )

    # 定义任务依赖:task2 在 task1 完成后执行
    task1 >> task2

在这个例子中:

  1. 我们从airflow模块导入了DAG类。
  2. 我们定义了一个简单的Python函数my_function
  3. 我们创建了一个名为my_dag的DAG实例,并设置了开始日期。
  4. 在DAG的上下文中,我们使用PythonOperator类定义了两个任务(task1task2),它们都调用my_function但传入不同的参数。
  5. 最后,我们使用>>运算符定义了任务间的依赖关系,确保task2task1完成后才运行。

Airflow架构概览

了解了如何定义DAG后,我们来看看支撑Airflow运行的简化架构。

Airflow的核心架构包含以下几个关键组件:

以下是各组件的主要功能:

  • 调度器/执行器:这是Airflow的核心。它读取DAG定义,并根据DAG文件中设定的调度计划,控制任务的执行顺序。
  • Web服务器:它提供了一个方便的Web用户界面,用于控制、监控任务和DAG的运行状态。
  • 数据库:用于存储所有DAG、任务执行记录等元数据。
  • 工作节点:负责实际执行任务代码的进程或机器。

工作流程如下:调度器从指定目录读取DAG文件(一个文件可以包含一个或多个DAG),然后根据依赖关系和调度计划,指挥工作节点执行任务。整个过程的状态信息会存入数据库,并报告给Web服务器以供查看。


使用Docker Compose运行Airflow

为了在本地运行包含所有组件的Airflow,Airflow官方提供了一个便捷的Docker Compose文件。

让我们查看一下这个用于在本地运行Airflow的Docker Compose文件:

文件主要包含以下部分:

  1. 共享配置:文件开头定义了被多个服务共享的配置,例如基础镜像、环境变量和挂载卷。
  2. 服务定义
    • postgres:用于元数据存储的PostgreSQL数据库服务。
    • redis:用作消息队列的缓存服务。
    • airflow-webserver:Airflow的Web服务器,它使用上方定义的共享配置。
    • airflow-scheduler:Airflow调度器。
    • airflow-worker:执行任务的工作节点。
  3. 数据持久化:文件末尾定义了一个卷(postgres-db-volume),用于确保PostgreSQL数据库的数据在容器重启后不会丢失。

使用这个Compose文件,我们可以通过一条命令在本地启动完整的Airflow环境。


总结

本节课中我们一起学习了Airflow的基础知识。我们了解到Airflow是一个用Python定义工作流(DAG)的平台,其架构包含调度器、Web UI、数据库和工作节点等核心组件。最后,我们看到了如何利用官方提供的Docker Compose配置,快速在本地搭建一个可运行的Airflow环境,为后续实际构建和管理数据管道奠定了基础。

072:使用Docker Compose运行Airflow 🚀

在本节课中,我们将学习如何使用Docker Compose在本地运行Airflow工作流管理平台。我们将从初始化数据库开始,逐步启动所有服务,并最终通过Web界面验证我们的DAG(有向无环图)是否成功运行。


现在,让我们使用Docker Compose在本地运行Airflow。

我们可以看到,项目中包含了由Airflow官方提供的Docker Compose文件。此外,我还创建了一些Airflow运行所必需的子目录。

以下是运行Airflow所需的三个关键目录:

  • DAGs目录:用于存放定义我们工作流的Python DAG文件。
  • logs目录:用于存储Airflow运行过程中产生的日志。
  • plugins目录:用于存放自定义的Airflow插件。

初始化数据库

设置Airflow的第一步是初始化其数据库。这可以通过Docker Compose文件中定义的一个特殊命令来完成,该命令名为 airflow-init

我们使用 docker compose 命令来运行Docker Compose。因此,初始化数据库的命令是:

docker compose up airflow-init

执行此命令后,系统会首先拉取PostgreSQL镜像作为数据库,接着拉取Redis镜像作为缓存层,最后拉取Airflow镜像本身。

所有容器创建完成后,Airflow的数据库就已准备就绪,可以运行了。


启动Airflow服务

上一节我们完成了数据库的初始化,本节中我们来看看如何启动完整的Airflow服务。

接下来,我们使用Docker Compose来启动Airflow。只需在终端中输入以下命令:

docker compose up

现在,Airflow服务已经启动并运行。我们可以打开一个网页浏览器,访问Airflow的Web用户界面进行查看。

这就是Airflow的Web UI。默认安装的Airflow有一个用户名为 airflow,密码同样为 airflow。在这里,我们可以看到Airflow自带的多个示例DAG。

我们也可以找到之前创建的简单示例DAG。这就是我们的 simple_example DAG。我们可以手动触发这个DAG,然后查看两个任务运行的结果。

我们还可以查看有向无环图(DAG)的可视化表示,其中任务间的依赖关系由箭头表示。此外,我们可以查看单个任务的详情。

例如,查看我们的第一个任务。我们可以查看它的运行日志。向下滚动,就能看到我们任务方法打印的输出信息。


课程总结

本节课中,我们一起学习了以下内容:

  • 介绍了Docker Compose作为一个容器编排工具。
  • 浏览了Docker Compose文件的一些基本元素。
  • 引入了Airflow这一工作流管理平台。
  • 实践了如何使用Docker Compose在我们自己的机器上本地运行Airflow。

应用Python数据工程:3:Kubernetes核心概念

在本节课中,我们将学习Kubernetes的几个核心概念。这些概念是理解和使用Kubernetes进行容器化应用部署与管理的基础。


集群

首先,我们来了解集群。集群是由一组节点组成的集合,这些节点由一个API统一控制。这个集群可以部署在您的虚拟机上,也可以存在于基于云的环境中,或者您自己的数据中心里。集群具备可扩展性,这是其重要特性之一。

部署

上一节我们介绍了集群,本节中我们来看看如何将应用部署到集群中。在部署方面,您需要将一个容器化的应用程序移入集群,然后启动该部署。这是一种非常常见的做法。

以下是部署的典型步骤:

  • 您可以从一个公共的容器注册表(例如DockerHub)开始。
  • 然后将该容器镜像移入您的部署系统。

探索

一旦应用部署完成并运行起来,您就可以对应用程序进行探索和迭代。这意味着您可以检查应用状态、查看日志,并根据需要进行修改和更新。

暴露

接下来是暴露应用。这里的核心思想是将您的应用程序暴露给外部世界,以便其他人能够使用它。通常,应用程序会通过一个公共端口对外提供服务。

扩缩容

应用暴露后,我们还需要考虑其应对负载变化的能力,这就是扩缩容。通过扩缩容,您能够响应特定事件(例如CPU使用率过高或内存不足),并为已部署的应用程序提供更多资源。

滚动更新

最后,一个非常常见的用例是发布应用程序的新版本,同时进行滚动更新。这意味着您可以在不中断服务的情况下,逐步迭代更新容器化应用程序的多个版本。


本节课中我们一起学习了Kubernetes的几个核心概念:集群部署探索暴露扩缩容滚动更新。这些是使用Kubernetes时最常见的场景。在接下来的课程中,我们将更深入地探讨其中一些场景。

074:Kubernetes集群架构 🏗️

在本节课中,我们将要学习Kubernetes集群的基本架构。我们将了解构成集群的核心组件,包括控制平面和工作节点,并解释它们如何协同工作。

集群架构概述

Kubernetes集群包含几种不同类型的资源。

首先,存在一个协调整个集群的控制平面。

在上图中,控制平面就是这里的紫色圆点。而节点则是运行在集群内部的工作单元。

因此,集群内部有多个工作节点,它们通过Kubernetes API进行通信。

从集群架构图中可以看到,所有节点基本上都处于这个控制平面的管理之下。根据您所构建的Kubernetes架构类型,这些节点会处理不同类型的工作。

节点的物理形态

一个节点也可以运行在一台物理计算机上。

它可以运行在虚拟机上,也可以运行在集群中。

因此,理解这个集群是一个逻辑上的概念集群非常重要。

但物理节点可能位于多种不同类型的位置。


本节课中我们一起学习了Kubernetes集群的基本架构。我们了解到集群由控制平面和工作节点组成,控制平面负责协调,节点负责执行具体工作。同时,我们也明白了Kubernetes集群是一个逻辑概念,其背后的物理节点可以分布在不同的计算环境中。

075:Kubernetes节点

概述

在本节课中,我们将要学习Kubernetes中的两个核心概念:Pod和节点。我们将了解它们是什么,它们之间的关系,以及它们如何共同构成Kubernetes集群的基础。

Pod与节点的概念

上一节我们介绍了Kubernetes的基本架构,本节中我们来看看Pod和节点这两个具体的组件。

Kubernetes Pod和节点是重要的概念。你可以在此图中看到,一个节点可以包含多个Pod。

我们知道节点可以运行在虚拟机上。它们可以运行在数据中心,也可以运行在云端。但在这个节点内部,你可以拥有许多不同的Pod,而这些Pod又可以包含许多不同的容器化应用、存储卷和IP地址。

在一个节点内运行多个Pod是典型做法。这里需要考虑的几点是:Pod是一个应用规格的逻辑主机,它可以包含紧密耦合的不同应用容器。

例如,一个前端和一个后端可以被包含在这种特定的配置中。另外需要考虑的几点是:Pod总是在一个节点上运行,而这个节点在Kubernetes中是工作机器。

节点可以是物理机,也可以是虚拟机,这取决于你配置了哪种类型的集群。

核心要点总结

以下是关于Pod和节点的关键信息列表:

  • Pod是应用的逻辑主机,包含一个或多个紧密耦合的容器。
  • 节点是运行Pod的物理机或虚拟机。
  • 一个节点可以托管多个Pod。
  • Pod总是在节点上运行。
  • 节点的类型(物理机/虚拟机)取决于集群配置。

总结

本节课中我们一起学习了Kubernetes的Pod和节点。Pod作为容纳应用容器的逻辑单元,运行在节点之上。节点是集群的工作单元,可以是物理或虚拟资源。理解这种“节点托管多个Pod”的关系,是掌握Kubernetes如何编排和管理容器化应用的基础。

076:Kubernetes服务部署

在本节课中,我们将要学习Kubernetes中的两个核心概念:部署服务。我们将了解如何通过kubectl命令来创建和管理部署,以及如何通过服务将应用程序暴露给外部世界。

部署:启动应用的第一步

在Kubernetes中,当你想要部署一个应用时,一个良好的起点是创建一个部署

你可以通过Kubernetes的命令行接口kubectl来创建和管理这个部署。kubectl的优势在于,它允许我们与Kubernetes控制平面进行交互和控制。

以下是使用kubectl创建部署的基本命令格式:

kubectl create deployment <部署名称> --image=<容器镜像>

一旦你成功创建并指定了这个部署,下一步就是关联一个服务

服务:暴露应用给外部世界

上一节我们介绍了如何创建部署,本节中我们来看看如何设置服务。

服务的作用是将你的应用程序暴露给外部世界。例如,你可以通过服务打开一个网络端口。

以下是设置服务并暴露端口的典型步骤:

  1. 创建服务:定义一个服务资源,将其与之前创建的部署关联起来。
  2. 暴露端口:在服务配置中指定要对外开放的端口。
  3. 访问应用:一旦端口被暴露,你就可以通过curl命令或运行功能测试、端到端测试来访问你的应用。

因此,在Kubernetes中设置应用的完整流程是:第一步创建部署,第二步设置服务并将应用暴露出去。

总结

本节课中我们一起学习了Kubernetes应用部署的核心流程。我们了解到,首先需要通过kubectl创建部署来定义和运行我们的应用实例。随后,我们需要创建一个服务资源,通过它来为部署的应用提供稳定的网络端点并对外开放端口,从而使外部客户端能够访问到我们的应用。这个“先部署,后服务”的两步法是发布Kubernetes应用的基础。

077:云开发工作空间优势 🚀

在本节课中,我们将探讨云开发工作空间这一新兴趋势,并分析其相较于传统本地开发环境的优势。我们将了解不同类型的云开发环境及其适用场景。

概述

云开发工作空间正成为软件工程、数据工程、数据科学和机器学习等多个领域的重要趋势。如果不使用基于云的开发环境,你可能会错过许多在本地笔记本电脑上无法获得的新功能。

传统本地开发环境

首先,让我们看看传统的笔记本电脑或工作站开发环境。这种环境存在几个关键问题。

  • 环境不确定性:没有保证一致的开发环境。
  • 存在不必要包:可能安装了你不想要的软件包。
  • 硬件成本高:获取GPU或大容量固态硬盘的成本可能很高。
  • 与部署环境不一致:本地环境通常与云端的生产部署环境不同,尽管容器技术可以部分解决此问题。

云开发环境概览

现在,让我们转向云端,看看一些基于云的开发环境。这些环境通常具有许多共同点。

以下是几种主流的云开发环境:

  • GitHub Codespaces:一个与GitHub深度集成的开发环境。
  • AWS Cloud9:亚马逊云科技的云端集成开发环境。
  • GCP Cloud IDE:谷歌云的云端集成开发环境。
  • Azure Cloud IDE:微软Azure的云端集成开发环境。

深入各类云环境

上一节我们介绍了云开发环境的整体情况,本节中我们来看看它们各自的特点。

GitHub Codespaces

GitHub Codespaces 具有独特的功能。它易于与 GitHub Actions(持续集成系统)集成。它也易于与 GitHub Copilot 集成,后者利用OpenAI Codex辅助你编写代码。整个集成与GitHub平台紧密耦合,是备受推荐的开发环境。

云端笔记本环境

对于偏好使用笔记本的工作流,也存在专门的云端环境。

以下是两种笔记本友好的云端选项:

  • Colab Notebooks:允许在云端构建使用GPU的Jupyter兼容系统,甚至可以使用专业版本。
  • AWS SageMaker Studio Lab:允许用户免费使用AWS平台提供的GPU来运行Jupyter笔记本。

AWS Cloud9 与其他云服务

AWS Cloud9 提供定制化功能,包括基于角色的权限管理,因此你无需在代码中硬编码API密钥。它还与 AWS LambdaAWS S3API Gateway 等服务深度集成,便于构建无服务器应用。

AWS还提供了一个更轻量级的版本,称为 AWS Cloud Shell,它甚至适合进行非常小型的软件工程任务,并且可以在Bash、Zsh或PowerShell之间切换。

其他云服务商也提供类似产品。GCP有自己的云编辑器和Cloud Shell。Azure也有自己的云编辑器和Cloud Shell。

核心优势与未来展望

我们介绍了多种具体的云开发环境,现在来总结其核心优势。

云开发工作空间的核心优势在于,它们提供了功能强大、可随时创建和销毁、且预装了所需工具的环境。这些环境深度集成云端服务,SDK已预装,并且与你的数据位于同一地理位置

例如,当你在咖啡馆需要处理TB级数据时,如果数据在云端,而你启动了一个云开发环境,那么你就直接与数据同地协作,无需来回传输数据。

总结

本节课中我们一起学习了云开发工作空间的优势。未来属于云开发工作空间,它提供了环境一致性、强大的计算资源、与云服务的深度集成以及与数据的同地协作能力。强烈建议开发者深入探索并利用这些环境。

078:GitHub生态系统核心概念 🚀

在本节课中,我们将学习GitHub生态系统的核心概念,了解它如何为机器学习和数据工程项目提供支持。我们将重点探讨四个关键方面:可复现性、GPU访问、AI编码助手以及持续集成与部署。


可复现性与Codespaces

上一节我们介绍了GitHub生态系统的概览,本节中我们来看看如何利用Codespaces实现环境的可复现性。可复现性对于团队协作和教学至关重要,它确保每个人都能在完全相同的环境中工作。

Codespaces是一个基于云的开发环境和工作空间,其核心是一个内置的容器镜像。这个镜像可以是Ubuntu、微软创建的镜像,或任何与Docker兼容的镜像。你可以通过 .devcontainer 配置文件来自定义它,以满足你的特定需求。

以下是Codespaces的三个核心优势:

  • 基于容器的环境:它提供了一个预配置的、可移植的开发环境。
  • 可定制的计算与存储:你可以配置Codespaces使用GPU、多核CPU或高内存机器。
  • 类生产环境:这使你能够在与生产环境相似的系统上进行测试和构建,减少部署时的意外问题。

GPU访问与深度学习

理解了环境可复现性后,我们来看看如何利用GitHub Codespaces访问GPU资源。这对于运行计算密集型的机器学习任务,如使用预训练模型或微调模型,非常有价值。

通过配置Codespaces使用GPU,你可以直接利用强大的计算资源,而无需购买昂贵的硬件。这为学习和实验降低了门槛。

借助GPU,你可以进行以下操作:

  • 使用预训练模型:例如,从Hugging Face下载模型并进行微调。Hugging Face经常与PyTorch配合使用。
  • 构建深度学习模型:你可以使用PyTorch或TensorFlow从头开始构建自己的模型。
  • 进行底层开发:甚至可以深入NVIDIA CUDA SDK,编写直接应用于GPU的函数。

AI编码助手:Copilot

在拥有了强大的计算环境和GPU资源后,如何更高效地编写代码呢?本节我们将介绍GitHub Copilot,这是一个AI驱动的编码助手,能显著提升开发效率。

Copilot能够根据你的项目上下文提供代码建议,甚至为你生成样板代码。通过与Copilot对话,你可以获得关于代码编写、工具构建等方面的实时建议。

Copilot能帮助你建立一个持续改进的良性循环:

  1. 获取建议:Copilot为你的代码提供补全和建议。
  2. 集成分析:你可以要求Copilot运行代码分析(如使用Pylint)、执行测试(如使用pytest)或在IPython中运行代码。
  3. 快速迭代:这个过程可以带来开发速度数倍的提升。

持续集成与部署:GitHub Actions

最后,当我们完成了代码开发与测试,如何将其自动化地部署到生产环境呢?这就是GitHub Actions的用武之地。它实现了持续集成(CI)和持续部署(CD)的自动化流程。

你可以在Codespaces环境中,通过Makefile执行标准的构建步骤,例如 make install(安装依赖)、make test(运行测试)和 make deploy(部署)。然后,利用GitHub Actions自动化这些步骤。

一个典型的自动化部署流程如下:

# 这是一个GitHub Actions工作流的简化概念描述
1. 代码推送到GitHub仓库。
2. GitHub Actions被触发,运行 `make install` 和 `make test`。
3. 测试通过后,执行 `make deploy`,将容器镜像推送到Amazon ECR(容器注册表)。
4. 镜像推送成功触发AWS App Runner(平台即服务),自动部署应用程序。

这个过程确保了你用于开发的环境(Codespaces)与最终部署的环境高度一致,使得从开发到生产的过渡非常平滑,符合CI/CD的最佳实践。


总结

本节课中,我们一起学习了GitHub生态系统中四个核心概念:Codespaces 提供了可复现的云开发环境;GPU访问 赋能了高效的深度学习工作流;Copilot AI助手大幅提升了编码效率;而 GitHub Actions 则实现了从代码到部署的自动化流水线。掌握这些工具,能为你的数据工程和机器学习项目提供一个强大、集成且高效的开发与运维基础。

079:使用GitHub模板

概述

在本节课中,我们将学习如何基于GitHub模板创建一个新的代码仓库。我们将了解模板的优势,并演示如何从现有模板创建仓库、进行自定义修改,以及如何将自己创建的仓库设置为模板供他人使用。

创建基于模板的新仓库

上一节我们介绍了GitHub模板的概念,本节中我们来看看如何实际操作。

让我们基于一个模板在GitHub上创建一个新的仓库。这里,我将查看“Microsoft Codespaces Teaching Template Pi”。可以看到这是一个公共模板。这个模板的好处在于,我可以基于它来自定义自己的工作流程。

要开始使用,我只需点击“Use this template”按钮,然后选择我的仓库,它就会将所有文件复制到这个新仓库中。

让我们开始操作。我将这个仓库命名为“Amlos Template”,因为我打算用它来创建我自己的模板。我们可以将其描述为“Emmalos Template”。然后我选择将其设为公开仓库。如果需要,我们也可以包含任何分支,但在这个例子中,只包含主分支就足够了。

自定义项目脚手架

现在,我们已经有了一个基于模板的仓库,接下来可以对其进行自定义。

当我为项目创建自己的脚手架时,我喜欢使用Makefile。因此,我可能会修改这个模板,添加一些不同的文件。我们可以快速完成这个操作,甚至可以直接通过这个界面创建文件。

例如,如果我在这里选择“Create new file”,并命名为“Makefile”,这就可以成为我添加到项目中的内容之一。同样,如果我想自定义开发容器(dev container),增强它或进行一些更改,我也可以这样做。

将仓库设置为模板

自定义完成后,我就可以将这个仓库设置为模板供他人使用。

接下来,我将进入仓库的设置页面。在仓库的设置中,我可以勾选“Template repository”选项。这样做的好处是,我可以将这个模板提供给学生或工作场所的其他人,他们将来也能使用它。

如果我们返回仓库主页,可以看到它现在显示为“Public Template”。将来,如果我想基于这个模板创建一个新项目,我只需选择“Use this template”即可。

GitHub还提供了一些额外的文档,名为“Creating a template repository”。如果你在创建自己的仓库时想要进行修改,将来可以参考这些文档。

总结

本节课中,我们一起学习了如何使用GitHub模板。我们了解了从现有模板创建新仓库的步骤,探讨了如何通过添加文件(如Makefile)来自定义项目脚手架,并最终学会了如何将自己的仓库设置为一个可复用的模板。掌握这些技能可以帮助你快速启动新项目,并促进团队内的代码复用和协作。

080:使用GitHub Codespaces定制开发环境

在本节课中,我们将学习如何利用GitHub Codespaces来定制一个开发环境模板。我们将从创建一个代码空间开始,逐步配置开发容器、安装扩展、设置个性化选项,并最终保存为一个可复用的模板。

概述

GitHub Codespaces提供了一个基于云的完整开发环境。本节将演示如何从一个公共模板仓库开始,通过选择机器配置、启用预构建容器、安装必要的扩展以及自定义开发容器配置文件,来创建一个满足特定需求的个性化开发环境。最终,这个环境可以被保存并分享给他人使用。

选择与启动代码空间

首先,我们有一个包含开发容器配置文件和GitHub Actions工作流的公共模板仓库。为了满足个人需求并修改此模板,我们将使用GitHub Codespaces。

进入仓库的“Codespaces”选项卡,默认会进入云端编辑模式。在这里,我们可以选择代码空间的配置。根据任务需求,可以从多种机器类型中进行选择。例如,进行多核概念教学时,可以选择16核的机器;而进行GPU相关的任务(如微调Hugging Face模型)时,则应选择配备GPU的机器。

我们选择GPU机型,然后点击“创建代码空间”。启动过程需要一些时间。

加速启动:预构建容器

为了加速未来代码空间的启动速度,我们可以启用“预构建容器”功能。这是一个非常实用的特性。

代码空间启动后,进入其“设置”。在“Codespaces”选项下,可以找到“预构建配置”的设置。我们启用此功能,并选择主分支(main branch)。这样设置后,每次向该分支推送代码时,系统都会自动重建此代码空间环境,从而显著提升后续的启动效率。

系统正在启动,我们可以看到它正在为开发环境配置各种选项。一旦环境设置完成,我们就可以开始定制模板了。

定制开发环境

关于这个特定环境,需要注意的一点是,我们可以通过修改开发容器(dev container)的配置文件来自定义它,这正是我们将要做的。

首先,我喜欢配置代码空间的外观。进入“设置”(Settings),找到“颜色主题”(Color Theme),将其更改为“Colorblind Beta”。这个主题提供了高对比度,具有良好的可访问性。我们也可以适当调整字体大小。

接下来,安装一些扩展来增强功能。进入“扩展”(Extensions)视图。
以下是需要安装的扩展:

  • Codium: 我选择安装其夜间构建版,以获取最新功能。
  • GitHub Copilot Labs: 这个扩展能提供代码翻译等辅助功能。

安装后,分别在这两个扩展上右键点击,选择“添加到开发容器”(Add to Dev Container)。这样做的好处是,将来其他人使用这个模板时,也能自动获得这些扩展功能。

配置Makefile与环境

现在,回到环境文件。我喜欢在项目中配置一个Makefile,并为其安装一个语法支持扩展。

首先,为Makefile安装一个扩展(例如“Makefile support”),并同样将其“添加到开发容器”。

然后,打开或创建项目根目录下的Makefile文件。我们可以在这里粘贴一些预定义的命令模板。
以下是一个Makefile的示例内容:

# 部署项目
deploy:
    @echo "运行部署脚本..."

# 安装软件依赖
install:
    pip install -r requirements.txt

# 运行测试
test:
    pytest

# 格式化代码
format:
    black .

# 代码检查
lint:
    flake8

通过这个Makefile,我们可以为使用者提供清晰的指导,告诉他们如何安装依赖、运行测试、格式化代码以及进行代码检查。这一切都封装在一个模板化的环境中。

此外,我们可以在终端验证环境资源。输入htop命令,可以看到这个环境拥有高内存配置。如果输入nvidia-smi命令,还可以检查GPU是否正常运行。

保存与提交更改

所有配置完成后,最后一步是将更改保存并提交到仓库,从而更新这个模板。

在终端中,运行以下命令:

git add .devcontainer
git add Makefile
git commit -m "更新开发容器配置和Makefile模板"
git push

现在,其他人就可以使用这个更新后的、功能更丰富的模板了。

总结

本节课中,我们一起学习了如何使用GitHub Codespaces定制开发环境。我们从选择机器配置和启用预构建容器开始,以提高效率;然后逐步安装了如Codium和Copilot Labs等扩展,并配置了Makefile来标准化项目操作。最后,通过提交更改,我们将这些个性化设置保存到了模板仓库中。这个过程使得创建和分享一个功能齐全、预配置好的开发环境变得非常简单。

081:使用OpenAI Whisper与GPU加速

概述

在本节课中,我们将学习如何在配备GPU的Codespace环境中,使用OpenAI的Whisper模型进行大规模音频文件的转录工作,并监控GPU资源的使用情况。


上一节我们介绍了如何在云端环境中部署工具,本节中我们来看看如何利用强大的GPU资源来运行AI模型。

这里有一个NVIDIA监控工具,可以让我查看此处NVIDIA GPU的完全利用率。

你可以看到这里的CUDA驱动版本是11.7,GPU使用率为43%。在另一个终端中,我正在运行Whisper,它能够利用Codespace上的GPU。我也能够转录非常大的文件,这得益于Codespace提供的存储空间。

对于使用基于GPU实例的数据科学和机器学习学生来说,这确实是一个进行GPU相关工作的绝佳环境。


我们也可以切换到这里查看每个进程。事实上,我不仅能够充分利用GPU,还能够使用这台六核机器,并利用这些重型GPU机器上可用的大内存空间。

你可以看到有110 GB内存可用。这意味着我实际上可以再运行几个转录任务,使用OpenAI的Whisper,同时监控我的资源。之后,如果我想对转录数据进行文本摘要或运行其他Hugging Face预训练模型,一切都可以顺利进行。


以下是利用该环境进行工作的关键优势列表:

  • GPU加速:Whisper等模型可以利用GPU(CUDA 11.7)显著提升处理速度。
  • 大存储空间:能够处理非常庞大的音频文件。
  • 强大计算资源:使用多核CPU(如六核)和大内存(110 GB)支持复杂任务。
  • 资源监控:通过工具(如nvidia-smi)实时监控GPU使用率,确保高效利用。
  • 集成工作流:为后续的文本处理任务(如摘要、其他模型微调)提供了准备好的数据基础。

总结

本节课中我们一起学习了在云端的Codespace环境中,如何配置并利用GPU资源来运行OpenAI Whisper进行音频转录。我们看到了监控GPU使用率的方法,并了解了该环境如何为数据科学和机器学习项目提供强大的计算能力和存储空间,支持从转录到后续高级文本处理的全流程工作。

082:使用Hugging Face微调模型

在本节课中,我们将学习如何使用Hugging Face这一流行的模型托管服务来微调预训练模型。我们将了解其核心功能,并逐步演示如何下载模型与数据集,并在GPU环境中进行微调。

概述Hugging Face平台

Hugging Face平台主要提供三个核心功能:模型数据集Spaces

  • 模型:这里托管了大量预训练模型。目前平台上有超过75,000个模型,并且数量还在快速增长。
  • 数据集:平台也提供了丰富的数据集,可用于模型训练和评估。
  • Spaces:这是一个用于展示和分享模型演示应用的功能。

这些模型关联着不同的任务,例如文本摘要、分类、问答等。我们可以通过浏览特定模型页面来试用这些功能。

探索与使用预训练模型

上一节我们介绍了Hugging Face的核心功能,本节中我们来看看如何具体使用一个模型。例如,如果我们进入“文本摘要”任务区,并找到Google的Pegasus模型,就可以直接在网页上运行示例并查看效果。

输入一段关于埃菲尔铁塔的文本,模型能够生成相应的摘要。这项服务被广泛用于生产环境和实验研究。

微调预训练模型的概念

了解了如何直接使用模型后,我们来看看如何根据特定需求定制模型。核心概念是:下载一个预训练模型,然后根据你的特定需求对其进行微调

Hugging Face提供了详细的教程,指导我们如何完成这个过程。通常,你需要从平台下载一个数据集,然后在启用了GPU的Github Codespace环境中进行模型微调。

微调实战:代码流程解析

现在,让我们深入一个具体的代码示例,看看微调是如何一步步实现的。

以下是微调过程的关键步骤代码概览:

# 1. 导入必要的库
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from datasets import load_dataset, load_metric

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/652627dc162f3ca87084dbf72fc3a9fe_2.png)

# 2. 加载数据集
dataset = load_dataset("glue", "mrpc")

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/652627dc162f3ca87084dbf72fc3a9fe_3.png)

# 3. 加载分词器并处理数据
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
def tokenize_function(examples):
    return tokenizer(examples["sentence1"], examples["sentence2"], truncation=True)
tokenized_datasets = dataset.map(tokenize_function, batched=True)

# 4. 加载预训练模型
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=2)

# 5. 定义评估函数(例如准确率)
metric = load_metric("glue", "mrpc")
def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    predictions = predictions.argmax(axis=-1)
    return metric.compute(predictions=predictions, references=labels)

# 6. 设置训练参数并开始微调
from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(output_dir="./results", evaluation_strategy="epoch")
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    compute_metrics=compute_metrics,
)
trainer.train() # 开始训练

这段代码展示了完整的流程:从加载数据和分词器,到加载预训练模型,最后使用Trainer进行微调。执行trainer.train()即可启动训练过程。

训练环境与监控

训练速度很大程度上取决于运行环境。使用CPU和启用GPU会有显著差异。

为了监控GPU在训练过程中的使用情况,可以使用nvidia-smi命令。下图展示了一个长时间微调任务的监控截图,可以看到GPU利用率达到了94%,这表明计算资源得到了充分利用。

总结

本节课中我们一起学习了Hugging Face平台的核心用途。我们了解了如何利用其托管的预训练模型和数据集,并重点掌握了微调的基本流程:即下载通用模型后,使用特定数据对其进行额外训练,使其适应新任务。整个过程可以通过Github Codespaces结合GPU加速来完成,是一种高效且直接的方法。

083:使用GitHub Copilot

概述

在本节课中,我们将学习如何使用GitHub Copilot来辅助编程。我们将探索两个主要功能:代码翻译和结对编程。通过实际操作,你将了解如何利用Copilot快速学习新语言、生成代码片段以及构建完整的命令行工具。


代码翻译功能

上一节我们介绍了GitHub Copilot的基本概念,本节中我们来看看它的代码翻译功能。

我已在一个启用了Copilot的代码仓库中。我们转到扩展区域,这里有一个“GitHub Copilot Labs”选项。它提供了一些实验性功能,其中包括代码翻译能力。同时,我也启用了GitHub Copilot扩展。有两个版本:Copilot和Copilot Nightly。我使用的是最新版本。我们将尝试这两个扩展。

为了开始使用,我们先查看一下GitHub Copilot Labs。它的作用是允许我们翻译代码。如果我点击这个选项并切换开关,它就会进行翻译。

以下是开始使用的步骤:

  1. 我可以从一个现有的仓库复制一些代码。我将创建一个名为loops的文件。
  2. 接着,我去另一个仓库复制一小段Bash代码。
  3. 我将这段代码粘贴到loops文件中。
  4. 现在我有了一段Bash代码。实际上,我们可以运行它。只需输入bash loops即可。

运行后,我们得到了预期的输出。现在,如果我想翻译这段代码,并了解它在Python中会是什么样子,我可以转到Copilot的“语言翻译”功能。看,它已经识别了这段代码。它能够高亮显示这里的文本。

Python是一个很好的尝试对象。一个好的做法是创建一个专门的翻译目录。

我们可以输入:

mkdir translate_copilot

然后,将loops文件移动到translate_copilot目录中,这样所有内容都在同一个目录下。接着,我进入这个translate_copilot目录。

从这里,如果我向Copilot请求建议,它会给我一个很好的例子。现在我可以创建一个Python版本的循环文件,我们称之为p_loops.py

我们做同样的事情。转到translate_copilot目录,找到我们的p_loops.py文件。让我们试一下。如果我运行python p_loops.py,我们得到了相同的结果。

这确实是一个非常棒的学习新语言的方式,特别是当你已经掌握一门语言时。它能让你非常快速地迁移代码。

实际上,我们可以超越Python和Bash。我们可以快速回到Copilot这里,抓取这段代码,然后说:现在我想把它翻译成Ruby。

让我们开始做吧。我们选择Ruby,看,我们也可以轻松得到一个Ruby脚本。我们将创建ruby_loops.rb文件。

这是一个在不同语言之间进行翻译的非常直接的过程,体验确实很棒。


结对编程与工作流构建

上一节我们体验了代码翻译,本节中我们来看看如何通过与Copilot结对编程来构建更复杂的工作流。

这里的核心思想是,Copilot就像另一位开发者。我们将创建一个名为ai_pair的目录,并进入该目录。

在这个ai_pair目录中,我将创建一个名为calc的文件。这个文件将用于向Copilot寻求帮助。

为了让提示更有效,我可以在文件顶部说明我们想要它做什么。例如,添加注释说明这个模块用于创建计算函数,比如加法和减法。随着我不断调整,提示会变得越来越好。

我们还可以在这里添加shebang行,这会告诉它我们最终会将其变成一个脚本。然后,我们可以快速将其设置为可执行文件。这样,我们应该就能直接运行它了。

开始后,看,它很聪明,已经知道我想做什么。这类似于我对另一个人类开发者说的话。一旦第一个函数完成,减法函数也随之而来,依此类推。既然我们已经有了几个函数,这就足够了。

现在我想做的是开始调整代码的方向,并告诉它我想构建一个命令行工具。例如,添加注释说明这个模块也将作为一个命令行脚本被调用,使用click库。

我们再次在这里提供一些引导。只需写上import click

要使用它,我需要做的就是告诉它我想创建一个组。我会说“构建一个click组”。然后它会为我构建出所有的样板代码。这样我就不用自己写这些样板代码了。它甚至会帮我写建议。

我们可以继续,并说明这是一个计算器应用。现在我已经构建好了这个,我还可以构建命令。它足够聪明,知道我的意图。我只需要灵活地填写它不知道如何完美填充的部分。

接下来,我将构建第二个命令。在这种情况下,它足够聪明,知道我前进的方向。我们可以继续构建其余部分。看,减法命令将使用这个函数。

现在,为了构建这个,我需要做的就是从命令行调用它。让我们快速试一下。我们可以查看帮助信息。我们有加法函数。我们可以计算2加2。我们也可以计算2加6。我们还可以使用减法函数。

如果我们想让它更花哨一点,一个简单的方法是让输出带有颜色。我可以直接告诉Copilot,它记住了很多样板代码,说“使用click的彩色输出调用add函数”。看,它稍微调整了一下。完美。然后这个函数可能也足够聪明,知道我想要彩色输出。确实如此。

现在,如果我返回,我们得到了每个工具的彩色输出。所以,使用Copilot的一个非常直接的方式就是温和地提示它,让它为你构建东西。从这个计算器工具,你可以看到它能多快地帮你构建出样板代码。


总结

本节课中,我们一起学习了GitHub Copilot的两个核心应用。首先,我们利用其代码翻译功能,快速将Bash脚本转换为Python和Ruby脚本,这为学习新语言提供了极大便利。其次,我们体验了与Copilot结对编程,通过逐步提示,引导它协助我们构建了一个功能完整的、带有彩色输出的命令行计算器工具。整个过程展示了Copilot如何理解开发者意图、生成样板代码并加速开发流程。

084:GitHub Actions入门教程 🚀

在本节课中,我们将学习如何为项目启用和使用GitHub Actions,以实现自动化构建、测试和部署流程。我们将通过一个具体的项目示例,了解其核心配置和工作原理。

概述

GitHub Actions是一个强大的持续集成和持续部署平台,允许开发者在代码仓库中直接自动化工作流程。通过编写YAML配置文件,可以定义在特定事件(如代码推送)发生时自动执行的一系列任务。

启用GitHub Actions的项目结构

让我们先观察一个已启用GitHub Actions的项目。任何配置了Actions的项目都会在 .github/workflows/ 目录下包含一个或多个YAML配置文件。

# .github/workflows/main.yml 示例结构
name: CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Install Dependencies
        run: make install
      - name: Lint Code
        run: make lint
      - name: Run Tests
        run: make test
      - name: Format Code
        run: make format

在上述配置中,我们定义了一个在 ubuntu-latest 环境中运行的作业。它也可以运行在GitHub Actions支持的任何其他容器、自定义容器甚至自定义开发空间中。每个步骤都通过 - name 来标识,并执行相应的 make 命令。

与Makefile的关联

上一节我们介绍了工作流配置文件,本节中我们来看看它如何与项目中的 Makefile 关联。

Makefile 中定义了构建过程的各个具体步骤。将GitHub Actions的YAML文件直接链接到 Makefile 的好处在于,你无需在Actions中重新思考要运行什么命令,只需运行与本地开发时相同的命令即可。

例如,如果我想在本地格式化代码,只需运行 make format。同样,当这个命令在GitHub Actions环境中运行时,也会执行完全相同的操作。这种一致性简化了开发到部署的流程。

以下是一个 Makefile 的示例内容:

# Makefile 示例
install:
    pip install -r requirements.txt

lint:
    flake8 .

test:
    pytest

format:
    black .

创建新的工作流

了解了基本结构后,我们来看看如何在GitHub上创建一个新的工作流。

在GitHub仓库页面,点击“Actions”选项卡。系统会提供几种不同的选项来帮助你开始:

  • 你可以选择“自行设置工作流”,这将提供一个基础模板。
  • 你也可以浏览GitHub提供的众多“建议的工作流”示例,例如用于发布Python包的模板。

虽然直接使用模板是一个不错的起点,但结合使用 Makefile 能更好地保持本地开发与云端自动化的一致性。这些示例也提供了遵循最佳实践的宝贵指南。

GitHub Actions的强大之处在于它能用于多种场景,包括自动化测试和部署,这正是它成为现代DevOps工作流核心的原因。

实战:观察工作流运行

现在,让我们通过一个实际操作来观察GitHub Actions是如何工作的。

首先,假设我们想测试项目中的某些更改。我们可以使用 git stash 命令暂存当前的修改。

git stash

接着,我们对项目中的某个脚本进行一个小修改。修改完成后,我们检查状态并提交这次更改。

git status
git add .
git commit -m “kicking off build”

当我们推送这次提交时,它会立即触发一个新的GitHub Actions构建任务。我们可以在Actions页面中逐步查看YAML文件中定义的每个步骤的执行情况。

对于部署流程,一个典型的推荐步骤顺序是:make install(安装依赖)、make lint(代码检查)、make test(运行测试),最后是 make deploy(执行部署)。GitHub Actions能够将代码推送到生产环境,是构建专业DevOps工作流的中心组件。

总结

本节课中,我们一起学习了GitHub Actions的核心概念和基本使用方法。我们了解了工作流YAML文件的结构、它与 Makefile 的关联、如何创建新工作流,并通过一个实战示例观察了其自动化执行过程。掌握GitHub Actions能显著提升代码集成与部署的效率和可靠性。

085:在GitHub Codespaces中运行Minikube 🚀

在本节课中,我们将学习如何在GitHub Codespaces环境中设置和运行Minikube,这是一个用于本地学习和开发Kubernetes的工具。我们将通过一系列步骤,从启动Minikube到部署一个示例服务,并最终清理环境。


概述

Kubernetes官方文档中有一个名为“Hello Minikube”的教程,指导用户如何在环境中进行设置。探索Kubernetes和容器的一个理想环境是GitHub Codespaces。本节教程将引导你使用一个预配置的代码仓库,在Codespaces中启动Minikube集群、部署应用并通过仪表板进行监控。


启动Minikube集群

首先,我们需要在GitHub Codespaces环境中启动Minikube。GitHub Codespaces的优势在于它提供了一个基于云的托管环境,与你的代码仓库直接映射,无需担心本地机器上产生失控进程。

以下是启动Minikube的步骤:

  1. 在终端中运行启动命令:

    minikube start
    

    此命令将在当前Codespaces环境中本地启动Minikube系统。

  2. 启动后,可以打开一个新的终端窗口,运行 htop 命令来监控系统资源使用情况,观察Kubernetes相关进程的运行状态。


启用指标服务器与仪表板

上一节我们启动了Minikube集群,本节中我们来看看如何启用附加功能以便更好地监控和管理集群。

  1. 启用指标服务器,它为集群提供资源使用指标:

    minikube addons enable metrics-server
    
  2. 创建Kubernetes仪表板的访问URL:

    minikube dashboard
    

    执行此命令后,会生成一个URL。在GitHub Codespaces中,你可以直接点击该链接,它将在浏览器中打开一个全面的Kubernetes仪表板。

在仪表板中,你可以查看工作负载状态、部署、Pod和副本集等信息,并与之交互。


部署示例服务

现在集群和仪表板已就绪,接下来我们部署一个示例服务到集群中。

以下是创建和查看部署的步骤:

  1. 使用 kubectl 命令创建一个新的部署。本例使用一个预构建的容器镜像:

    kubectl create deployment hello-node --image=registry.k8s.io/echoserver:1.4
    
  2. 验证部署是否成功。有两种方法:

    • 通过仪表板:在仪表板的“部署”部分查找名为 hello-node 的部署。
    • 通过终端:运行以下命令查看部署和Pod状态:
      kubectl get deployments
      kubectl get pods
      


暴露与访问服务

部署完成后,我们需要将服务暴露出来,以便能够从外部访问它。

以下是暴露和访问服务的步骤:

  1. 将部署的服务暴露为一个NodePort类型的Kubernetes服务:

    kubectl expose deployment hello-node --type=NodePort --port=8080
    
  2. 获取服务的访问信息:

    • 使用 kubectl 命令查看服务详情,获取IP地址和端口。
    • 一个更便捷的方法是使用Minikube命令直接获取服务的可访问URL:
      minikube service hello-node --url
      
      复制输出的URL,在浏览器中打开或使用 curl 命令测试,服务应返回一个包含时间戳的响应。

清理环境

实验结束后,清理资源是一个好习惯,可以释放系统资源。

以下是清理环境的步骤:

  1. 删除创建的服务:
    kubectl delete service hello-node
    
  2. 删除部署:
    kubectl delete deployment hello-node
    
  3. (可选)停止Minikube集群:
    minikube stop
    

总结

本节课中我们一起学习了在GitHub Codespaces环境中运行Minikube的完整流程。我们从启动Minikube集群开始,然后启用了指标服务器并访问了仪表板。接着,我们部署了一个名为 hello-node 的示例应用,将其服务暴露给外部网络,并通过浏览器和命令行两种方式进行了访问验证。最后,我们演示了如何删除服务和部署以清理环境。这个过程展示了在隔离的云开发环境中安全、便捷地学习和操作Kubernetes的基本方法。

086:使用Minikube部署服务 🚀

在本节课中,我们将学习如何将一个使用FastAPI编写的微服务容器化,并使用Minikube在本地Kubernetes环境中进行部署和管理。我们将从代码结构开始,逐步完成本地运行、容器构建、推送到镜像仓库,最终在Minikube集群中部署和访问服务的全过程。

项目结构概述 📁

首先,我们来看一下这个微服务项目的代码结构。项目托管在一个GitHub仓库中,核心是一个FastAPI应用。

以下是项目的主要组成部分:

  • main.py:这是微服务的主文件,包含了应用的主要逻辑和API路由定义。
  • logic/ 目录:这个目录下存放着具体的业务逻辑函数。例如,有一个函数可以随机返回不同的水果名称。你可以在这里构建任意数量的功能模块,然后在主文件中通过路由调用它们。
  • Dockerfile:这是容器化应用的关键文件。它定义了如何将我们的Python应用及其依赖打包成一个Docker镜像。
  • API文档:由于使用了FastAPI框架,应用自动生成了交互式API文档,可以通过访问 /docs 端点来查看和测试所有API接口,无需额外构建前端界面。

这个结构为我们提供了灵活性:我们可以将容器镜像推送到镜像仓库(如Docker Hub),也可以在本地或云端的Kubernetes环境中运行它。

本地运行与测试 🔧

上一节我们介绍了项目结构,本节中我们来看看如何本地运行这个FastAPI应用。

在GitHub Codespaces环境中,我们可以直接运行主程序。执行命令 python main.py 后,应用将在本地启动。

python main.py

服务启动后,默认运行在 8080 端口。通过浏览器访问,可以看到基础的“Hello World”响应。更重要的是,访问 /docs 路径可以打开Swagger UI界面,这是一个强大的工具,允许我们直接查看和测试所有已定义的API端点。

例如,我们可以测试“获取随机水果”的端点,它会返回如“orange”这样的结果。我们也可以测试“搜索维基百科”的端点,通过提交一个包含搜索词(如“Obama”)的请求体,API会返回相关的搜索结果。

容器化与推送至Docker Hub 🐳

现在,我们已经验证了应用可以在本地正常运行。接下来,我们将利用项目中的 Dockerfile 将其容器化。

容器化的好处是能将应用及其运行环境打包成一个标准、可移植的镜像。我们可以使用Docker命令在本地构建这个镜像。

docker build -t your-username/fastapi-app:latest .

构建完成后,我们可以将这个镜像推送到公共或私有的容器镜像仓库,例如Docker Hub。这样做意味着在任何支持Docker的环境中,我们都可以通过一条简单的命令拉取并运行这个完全一致的应用环境,而无需关心宿主机上是否安装了Python或相关依赖包。

docker push your-username/fastapi-app:latest

使用Minikube在Kubernetes中部署 🚢

虽然将容器推送到仓库已经很方便,但我们的目标是利用Kubernetes来编排和管理容器化应用。Minikube是一个工具,它能在本地轻松创建一个单节点的Kubernetes集群,非常适合学习和测试。

以下是使用Minikube部署我们服务的步骤:

  1. 启动Minikube集群:首先,我们需要启动一个本地Kubernetes环境。

    minikube start
    
  2. (可选)启用指标服务器:为了获取集群资源使用的额外指标,可以启用metrics-server插件。

    minikube addons enable metrics-server
    
  3. 创建Deployment:Deployment是Kubernetes中定义应用部署和更新策略的资源对象。我们使用 kubectl 命令创建一个Deployment,并指定从Docker Hub拉取我们之前推送的镜像。

    kubectl create deployment hello-fastapi --image=your-username/fastapi-app:latest
    

    执行后,可以使用 kubectl get deployments 命令查看Deployment的状态,确认其已成功创建并运行。

  1. 暴露Service:Deployment管理着Pod(容器组),但为了能从集群外部访问到我们的应用,需要创建一个Service(服务)来提供稳定的网络端点。

    kubectl expose deployment hello-fastapi --type=NodePort --port=8080
    

    执行 kubectl get services 可以查看Service的详细信息,包括被分配的外部访问端口。

  2. 访问应用:Minikube提供了一个便捷的命令来获取Service的可访问URL。

    minikube service hello-fastapi --url
    

    复制该URL到浏览器,或者使用 curl 命令,即可访问到运行在Kubernetes集群中的FastAPI服务,验证其是否返回“Hello FastAPI”等预期响应。

清理资源 🧹

在完成测试后,及时清理资源是一个好习惯。我们可以按创建资源的相反顺序进行删除。

以下是清理步骤:

  • 删除Service:kubectl delete service hello-fastapi
  • 删除Deployment:kubectl delete deployment hello-fastapi
  • 停止Minikube集群:minikube stop

总结 📝

本节课中我们一起学习了微服务从代码到部署的完整流程。我们首先分析了一个FastAPI微服务的项目结构,并在本地成功运行和测试了它。接着,我们使用Dockerfile将应用容器化并推送到了Docker Hub镜像仓库。最后,我们利用Minikube工具在本地搭建了Kubernetes环境,通过创建Deployment和Service,成功地将我们的容器化应用部署到了Kubernetes集群中,并实现了从外部的访问。这个过程涵盖了现代云原生应用部署的核心步骤,是进行更复杂数据工程应用编排的基础。

087:使用GitHub Codespaces构建微型Bash容器 🐳

在本节课中,我们将要学习如何使用GitHub Codespaces来构建一个微型的Bash容器。我们将从创建一个简单的Dockerfile开始,构建一个极小的容器镜像,并学习如何运行和分发它。通过这个过程,你将理解容器的基本概念及其作为独立运行环境的价值。

概述

容器技术允许你将应用程序及其所有依赖项打包在一起,确保它在任何环境中都能以相同的方式运行。本节我们将从一个最简单的例子入手:将一个Bash命令行工具容器化。

准备工作与环境搭建

首先,我们需要一个开发环境。我们将使用GitHub Codespaces,它提供了一个预配置的、基于云的开发环境。

上一节我们介绍了课程目标,本节中我们来看看如何设置我们的开发环境。

我选择了一个Python项目模板作为起点,并将其命名为“container template”。这样命名是因为我们后续会大量使用容器。启动这个Codespace后,系统会自动进行构建和配置。同时,为了后续演示,我提前准备了一些有用的容器示例代码。

理解容器基础

当人们听到“容器”这个词时,常常会问:容器是什么?我为什么需要关心它?因此,在环境构建的同时,我们先快速过一些容器的基础知识。

容器的核心思想是创建一个独立的运行时环境。你只需要一个Dockerfile来定义这个环境。在这个环境中,你可以添加任何你需要的工具或应用,然后将其分发给他人或在不同地方使用。这是一个极佳的入门演示。

创建容器项目

现在我们的Codespace环境已经准备就绪。让我们开始创建我们的第一个容器项目。

首先,清理一下模板自带的文件,然后创建一个专门用于本项目的目录。

以下是创建项目目录和初始文件的步骤:

  • 创建一个名为 tiny-computer 的目录。
  • 进入该目录。
  • 创建一个空的 Dockerfile 文件。

编写Dockerfile

Dockerfile是构建容器的蓝图。我们将使用Alpine Linux作为基础镜像,因为它非常小巧。

我们将创建一个简单的Bash脚本作为我们的“应用”,并将其添加到容器中。

以下是创建应用脚本和Dockerfile的步骤:

  • 创建一个名为 message 的可执行Bash脚本。
  • 脚本内容很简单:重复打印传入的参数三次。
  • 我们还可以创建一个 README.md 文件作为文档。

现在,让我们编写Dockerfile。它将基于Alpine镜像,并将我们的 message 脚本复制到容器内的 /usr/local/bin 目录,使其可以在任何地方被调用。

Dockerfile 示例代码:

FROM alpine:latest
COPY message /usr/local/bin/message
RUN chmod +x /usr/local/bin/message

构建与运行容器

有了Dockerfile,我们就可以构建容器镜像了。

在项目目录下,运行 docker build -t tiny-app . 命令。这个命令会读取当前目录的Dockerfile并构建一个名为 tiny-app 的镜像。

构建完成后,使用 docker image ls 命令查看镜像列表。你会发现这个镜像非常小,大约只有10MB,但它包含了一个完整的、可运行的Linux操作系统环境。

现在,让我们运行它。有两种主要方式:

  1. 交互式Shell方式:使用 docker run -it <镜像ID> /bin/sh 命令。这会进入容器的Shell,你可以在里面直接执行 message 命令,就像在一个微型Linux系统里操作一样。退出后,容器内的临时更改会丢失,这体现了其“沙盒”特性。
  2. 直接执行命令方式:使用 docker run <镜像名> message “Hello” 命令。这可以直接在容器外部调用容器内的应用,并看到输出结果,无需进入Shell。

分发容器镜像

自己使用容器很方便,但容器的强大之处在于易于分发。你可以将构建好的镜像推送到像Docker Hub这样的容器注册中心。

例如,你可以登录Docker Hub,然后使用 docker push <你的用户名>/tiny-app 命令推送镜像。之后,任何人只需执行 docker pull <你的用户名>/tiny-appdocker run <你的用户名>/tiny-app message “Hi” 就能运行你的工具,无需关心他们的本地环境如何。

这是一个非常实用的技巧:你可以用Alpine这样轻量的基础镜像,打包一个小脚本,推送到Docker Hub,就能轻松地分享或部署你的工具。

总结

本节课中我们一起学习了容器的基本概念和实战操作。我们从在GitHub Codespaces中设置环境开始,创建了一个包含简单Bash脚本的Dockerfile,并使用它构建了一个微型的Alpine Linux容器。我们探索了如何以交互模式或直接执行命令的方式来运行容器,并了解了如何将容器镜像推送到Docker Hub进行分发。这个微型Bash容器的例子展示了容器技术如何为工具和应用程序提供一致、隔离且可移植的运行环境。

088:在Cloud9中用Python构建FastAPI微服务 🚀

在本节课中,我们将学习如何使用FastAPI框架构建一个简单的微服务,并将其部署到AWS App Runner平台。整个过程将涵盖从本地开发环境设置到云端部署的完整流程。


环境与项目准备

上一节我们介绍了微服务的基本概念,本节中我们来看看如何具体搭建一个FastAPI服务。我使用AWS Cloud9作为开发环境,因为它非常适合在AWS云平台上部署微服务。我们最终将使用AWS App Runner进行部署,这是一个新兴且优秀的微服务托管框架。

我的项目仓库是NOAAgi-fastAPI,它使用了FastAPI框架。FastAPI是一个非常流行的框架,具有许多优点,包括类型提示支持和集成的Swagger文档,使用起来非常简单。

以下是我的项目环境设置:

  • 我有一个Python虚拟环境。
  • 我喜欢为项目搭建一个脚手架结构。例如,我使用一个Makefile来管理安装、测试、代码格式化和代码检查任务。
  • 我还使用了GitHub Actions来实现持续集成,自动测试代码。我强烈建议你也这样做。

你可以在NOAAgi-fastAPI仓库中查看这些配置的细节。


编写并运行FastAPI服务

接下来,我将运行这个微服务。让我们先看一下核心代码。

首先,从fastapi导入FastAPI:

from fastapi import FastAPI

我定义了一个简单的“hello world”路由:

@app.get("/")
def hello():
    return {"message": "Hello Duke"}

这条消息来自我在杜克大学讲授的云计算课程。

然后,我定义了一个加法端点:

@app.get("/add")
def add_numbers(a: int, b: int):
    total = a + b
    return {"total": total}

它接收两个整数参数,并返回它们的和。

最后,服务被配置为运行在外部接口的8080端口上。

运行服务非常简单。进入微服务目录后,只需执行:

python main.py

服务启动后,我可以在新的终端中使用curl命令测试它。这是一个在基于终端的环境中非常有用的技巧。

测试根路径:

curl http://localhost:8080/

返回{"message":"Hello Duke"},工作正常。

测试加法端点:

curl "http://localhost:8080/add?a=2&b=2"

返回{"total":4},功能正确。


部署到AWS App Runner

现在服务已在本地运行,我们来看看如何将其部署到AWS App Runner环境。幸运的是,这个过程非常直接。

以下是部署步骤:

  1. 在AWS控制台创建App Runner服务。
  2. 选择“源代码仓库”作为部署源。
  3. 连接并选择我们的NOAAgi-fastAPI仓库。
  4. 配置部署设置。我选择“手动”部署以简化流程,运行时选择“Python 3”。
  5. 构建命令设置为pip install -r requirements.txt,启动命令设置为python main.py。这与我们在Cloud9环境中的操作一致。
  6. 为服务命名,例如“microservice-2”,然后点击“创建并部署”。

部署过程大约需要五分钟。完成后,App Runner会提供一个完全加密的默认域名来访问服务。


测试与验证部署的服务

部署完成后,我们可以通过提供的URL访问服务。FastAPI的一个很棒的特性是内置了Swagger文档。

访问{你的服务URL}/docs,可以看到自动生成的API交互文档。例如,我可以点击“add”端点,选择“Try it out”,输入参数a=2b=2,然后执行。界面会显示对应的curl命令、请求URL和响应详情,这对于构建数据工程或机器学习API非常有用。

同样,我也可以直接在浏览器中测试完整路径,例如访问{你的服务URL}/add?a=2&b=2来验证加法功能。


总结

本节课中我们一起学习了使用FastAPI构建Python微服务的完整流程。我们从设置Cloud9开发环境开始,编写了一个包含“hello world”和加法功能的简单API。接着,我们探索了如何将这个本地服务部署到AWS App Runner平台,并利用FastAPI自带的Swagger UI对部署后的服务进行了测试和验证。整个过程展示了从开发到部署的现代化微服务实践。

089:将FastAPI-PyTorch容器化应用部署到AWS App Runner 🚀

在本节课中,我们将学习如何将一个结合了FastAPI和PyTorch的机器学习应用容器化,并部署到AWS的App Runner服务上。整个过程涵盖了从本地开发、Docker容器构建、推送到AWS容器仓库,到最终在云端运行服务的完整流程。


环境准备与代码概览

首先,我们进入一个包含PyTorch和FastAPI应用的新代码仓库。这个应用已经配置好,可以部署到AWS App Runner这个平台即服务产品。

我们可以在Github Codespaces环境中直接运行此项目。当前环境已经启动。让我们查看一下项目的requirements.txt文件,其中列出了所需的依赖包。

fastapi
uvicorn
pillow
torch
torchvision

这些依赖包已经准备就绪。此外,我们还需要确保PyTorch已正确安装,当前环境已满足此条件。


项目结构与核心代码

上一节我们检查了运行环境,本节中我们来看看项目的核心文件。

项目包含一个Dockerfile,用于构建Docker镜像。这个过程非常简单。

以下是应用的主要代码文件app.py的核心逻辑:

  1. 导入必要的库:包括FastAPI、PyTorch及其工具库。
  2. 初始化模型:加载一个预训练的PyTorch模型。
  3. 设置FastAPI应用:创建FastAPI应用实例。
  4. 定义辅助函数
    • transform_image: 处理上传的图片,将其转换为模型可接受的张量格式。
    • get_prediction: 使用加载的模型对处理后的图片进行预测。
  5. 定义API端点
    • /: 一个简单的“Hello World”端点,用于调试。
    • /predict: 主要的预测端点,接收图片文件,调用辅助函数进行处理和预测,并返回结果(例如,判断图片是否为猫)。

代码的最后部分启动了FastAPI应用。


本地运行与测试

现在,让我们在本地运行这个应用,以确保一切正常。

在终端中执行命令:

python app.py

应用启动后,我们可以在浏览器中访问其提供的交互式API文档。访问/docs路径,即可看到Swagger UI界面。

在Swagger界面中,我们可以测试/predict端点。选择一张本地图片(例如一张埃及猫的图片)进行上传并执行。服务成功返回了预测结果,确认了图片内容为猫。

至此,我们拥有了一个功能完整的、可用于MLOps场景的FastAPI + PyTorch服务。


构建与推送Docker镜像到AWS ECR

为了将应用部署到AWS App Runner,我们需要先将应用容器化,并将镜像推送到AWS的Elastic Container Registry。

以下是具体步骤:

  1. 在AWS控制台创建ECR仓库:我们创建一个名为pytorch-fastapi的私有仓库。
  2. 准备AWS Cloud9构建环境:Cloud9是AWS提供的云端IDE,类似于Github Codespaces,方便我们进行构建。在Cloud9中克隆项目代码仓库。
  3. 设置Python虚拟环境并安装依赖
    python3 -m venv venv
    source venv/bin/activate
    pip install -r requirements.txt
    
  4. 可选:调整Cloud9环境磁盘大小:为了顺利构建容器,有时需要扩大Cloud9实例的存储空间。
  5. 构建Docker镜像:使用项目中的Dockerfile构建镜像。
    docker build -t pytorch-fastapi .
    
  6. 本地测试Docker容器:运行刚构建的镜像,并在Cloud9的预览功能中访问应用,重复之前的预测测试,确保容器化后的应用工作正常。
    docker run -p 8080:8080 <image_id>
    
  7. 标记并推送镜像到ECR:首先登录ECR,然后为本地镜像打上ECR仓库的标签,最后推送。
    aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account_id>.dkr.ecr.<region>.amazonaws.com
    docker tag pytorch-fastapi:latest <account_id>.dkr.ecr.<region>.amazonaws.com/pytorch-fastapi:latest
    docker push <account_id>.dkr.ecr.<region>.amazonaws.com/pytorch-fastapi:latest
    

在AWS App Runner上部署服务

镜像推送成功后,我们就可以在AWS App Runner上创建服务了。

以下是部署流程:

  1. 在AWS控制台进入App Runner服务,点击“创建服务”。
  2. 选择“容器注册表”作为源代码,并找到我们刚刚推送到ECR的镜像(pytorch-fastapi:latest)。
  3. 配置服务:
    • 服务名称:例如 pytorch-container-service
    • 部署设置:选择“自动部署”,这样每次推送新镜像到ECR时,服务会自动更新。
    • 计算配置:根据需求选择适当的CPU和内存规格(例如,为机器学习推理选择较高的配置)。
  4. 创建服务后,App Runner会自动从ECR拉取镜像并启动容器。我们可以在控制台查看部署日志,监控健康检查状态。
  5. 服务启动完成后,App Runner会分配一个HTTPS端点(域名)。这个域名是加密的,提供了安全的访问方式。

验证云端部署

现在,我们的机器学习微服务已经运行在云端。我们可以通过App Runner提供的域名来访问它。

  1. 在浏览器中打开服务域名后的/docs路径(例如,https://your-service-id.region.awsapprunner.com/docs)。
  2. 再次打开Swagger UI界面,测试/predict端点。
  3. 上传同一张猫的图片并执行预测。服务成功返回了预测结果。

这表明我们已成功将一个生产级的机器学习微服务,通过简单的几步操作,部署到了AWS云平台,并且可供其他用户或系统访问。


本节课中我们一起学习了将FastAPI与PyTorch结合的机器学习应用进行容器化,并利用AWS Cloud9构建环境、ECR容器仓库和App Runner无服务器容器服务,实现从本地开发到云端部署的完整流程。这套方法能高效地构建和部署可扩展的MLOps应用。

090:容器编排方案

在本节课中,我们将学习基于容器的部署服务管理方案。我们将探讨从本地开发到云上生产环境的完整流程,并比较不同云服务商提供的托管容器服务选项。

概述

在云原生应用开发中,容器化部署是标准实践。开发者通常在本地或云端开发环境中构建和测试容器,然后通过构建系统将其推送到生产环境。整个过程涉及容器注册表、托管容器服务等多个环节。理解这些组件如何协同工作,对于高效、经济地部署应用至关重要。

容器化部署流程

上一节我们介绍了容器化的基本概念,本节中我们来看看一个典型的、基于云的容器化部署工作流是如何运作的。

整个流程可以概括为以下几个核心阶段:

  1. 开发与本地测试:在云端开发环境(如 AWS Cloud9、Google Cloud Workstations 或 GitHub Codespaces)或本地环境中进行开发,并构建和测试容器。
  2. 构建与推送:通过构建系统(如 GitHub Actions、AWS CodeBuild)将容器镜像推送到容器注册表。
  3. 部署与运行:从容器注册表拉取镜像,并在托管的容器服务中运行。

以下是该流程中涉及的关键组件及其作用:

  • 开发环境:用于编写代码和构建初始容器镜像的地方。
  • 构建系统:自动化流程,负责构建最终的容器镜像并将其推送到注册表。
  • 容器注册表:存储和管理容器镜像的仓库,例如 Docker Hub 或云服务商提供的注册表(如 AWS ECR、Google Container Registry)。
  • 托管容器服务:在云上运行和管理容器化应用的服务。

托管容器服务选项

理解了基本流程后,我们来看看流程的终点——托管容器服务。云服务商提供了多种不同抽象级别的服务。

核心原则是:尽可能使用最高级别的托管服务。这通常更高效且成本更低,因为云服务商负责了底层基础设施的繁重管理工作。

以下是不同云平台的主要托管容器服务示例:

  • 亚马逊云科技 (AWS)
    • Amazon EKS (Elastic Kubernetes Service):托管的 Kubernetes 服务。你无需管理 Kubernetes 控制平面。
    • Amazon ECS (Elastic Container Service):AWS 自研的容器编排服务,与 AWS 其他服务深度集成。
  • 谷歌云 (Google Cloud)
    • Google Kubernetes Engine (GKE):托管的 Kubernetes 服务。
    • Google Cloud Run:一个更高级别的无服务器容器平台。你只需提供容器镜像,它就能自动运行和扩缩容,部署命令极其简单。
  • 其他云平台:如微软 Azure 的 AKS (Azure Kubernetes Service),其模式也类似。

总结与最佳实践

本节课中我们一起学习了基于容器的云上部署架构。

总的来说,在处理云基系统时,你应该预期会用到上述的架构覆盖。一个关键的最佳实践是:通常你不应该通过自建的、自我管理的 Kubernetes 集群来部署应用。相反,你应该利用云服务商提供的托管服务,让领域的专家为你完成繁重的基础设施管理工作,从而使你能够更专注于应用本身的开发与业务逻辑。

选择哪种具体服务,取决于你对控制粒度、易用性以及与特定云生态集成的需求。对于大多数应用场景,从高级别服务(如 Cloud Run)开始尝试,是快速上手的有效途径。

091:GCP Cloud Run 服务部署教程 🚀

在本节课中,我们将学习如何在 Google Cloud Platform 上使用 Cloud Run 服务来部署一个容器化的 Python 应用。我们将从零开始,通过 Cloud Shell 编辑器创建一个应用,在本地模拟器中运行和调试,最后将其部署到生产环境。


在 Google Cloud 控制台中,提供了 Cloud Run 服务。在完全托管的平台上运行容器的方法之一,就是使用像 Cloud Run 这样的服务。事实上,你可以直接点击按钮开始使用。另一个有趣的选择是从头开始创建。

如果我们选择激活 Cloud Shell,它的一个优点是,我可以打开一个编辑器,获得一个专为构建容器应用而定制的完整 IDE,这些应用随后可以被推送到生产环境。从 Google Cloud 编辑器中可以看到,这里有很多简洁的功能,包括启动终端和进行各种操作的能力。

但这些基于云的开发环境更有趣的一个方面是这个菜单,你可以在这里选择不同的服务并以原型化的方式构建它们。接下来,让我们选择 Cloud Run。

就在这里。如果我继续并授权它,它将设置一个允许我原型化 Cloud Run 应用的环境。我们继续操作,它会显示“欢迎来到 Cloud Shell”。我们该怎么做呢?我们可以创建一个新的 Cloud Run 应用。让我们继续这样做,并且我们可以选择一个模板。

我们继续选择 Python Cloud Run 模板,然后点击创建新应用。好了,它将会为我们下载环境,完成所有设置。一旦我进入这个环境,真正的好处是我有文档,这里有初步的设置。事实上,我甚至已经有了一个构建好的 Dockerfile。

这是获取如何构建某物想法的好方法,因为 Google 的专家向你展示了具体要构建什么,他们甚至使用了一个非常酷的 outpine 容器,这是一个最小尺寸的容器。我还可以查看这里的样板代码。你可以看到这是一个非常简单的服务,但它稍后将被推送到一个托管的容器编排服务中,而我无需做任何工作。

那么,我们如何让这个东西运行起来呢?首先,我们想使用云模拟器在本地运行应用,然后将其部署到 Cloud Run。我认为这是开始使用它的更好方法之一。那么我们该怎么做呢?

你点击云状态栏并选择“在云模拟器上运行”。这样做是在本地运行 minikube。让我们继续这样做。如果我们转到状态栏这里并选择我们的 Cloud Run 应用,我们可以直接说“在本地 Cloud Run 模拟器上运行应用”。让我们继续看看这将如何工作。

很好,它显示构建环境为本地。我们继续操作。它会询问一些设置。我们可以直接继续。这个本地服务真正酷的地方在于,当我实际原型化代码时,我可以让它自动重启。这是一种非常流畅的开发方式,基本上就是开发容器化应用,而且我可以实时编辑,它会为我重建容器。

正如我之前提到的,每当我想要部署它时,它就会直接推送到生产环境。这需要一点时间来加载。好了,现在我们已经设置好了,真正酷的是它在监视变化。一方面,我还可以预览它。所以如果我悬停在这个上面,我们可以继续查看,非常酷,对吧?我有一个应用在运行。

现在如果我想在本地调试它,我能做的一件很酷的事情是,我们可以看到它在运行。然后我可以说,看,我更改了这个。如果我保存它,自动地,看,它重启了。如果我再次回到这里的服务 URL 并查看它。

好了,我更改了它。这真是一个用于原型化基于云的服务的绝佳环境。现在让我们回到控制面板,实际上,让我们终止这个进程。然后我们能做的是,我们可以将其部署到生产环境。

为了做到这一点,我可以做的是继续选择“部署到 Cloud Run”。这实际上会直接将此推送到生产环境。真的,一旦你有了一个容器,使用像 Cloud Run 这样的服务设置好你的微服务就非常直接了。你可以在这里看到实际部署其余代码的步骤。


本节课中,我们一起学习了在 GCP 上使用 Cloud Run 服务部署 Python 应用的全过程。我们从在 Cloud Shell 编辑器中创建项目开始,使用模板生成了包含 Dockerfile 的代码。接着,我们利用本地 Cloud Run 模拟器运行和调试应用,体验了代码热重载的便捷性。最后,我们了解了如何一键将调试好的容器化应用部署到 Cloud Run 生产环境。整个过程展示了如何在一个完全托管、无需管理基础设施的平台中,高效地开发、测试和部署微服务。

092:在Cloud9中用C#语言构建微服务

概述

在本节课中,我们将学习如何利用AWS云服务构建一个完整的、容器化的.NET微服务开发与部署工作流。我们将使用Cloud9作为云端开发环境,将应用容器化后推送到Elastic Container Registry (ECR),并通过App Runner进行自动化部署,最后使用Cloud Shell进行测试。

AWS容器化工作流介绍

让我们先了解一下AWS的容器化工作流。下图展示了我们将要使用的四个核心服务:

这四个服务是:AWS Cloud 9Amazon Elastic Container Registry (ECR)AWS App RunnerCloud Shell。它们共同构成了一个纯云端的开发环境。这意味着开发者无需接触任何本地硬件,即使是在性能较弱的设备(如Chromebook的网页浏览器)上,也能借助Cloud9的强大能力进行开发。

这种环境的优势在于,开发者可以在一个与最终部署环境高度相似的本地化环境中进行开发,并且与ECR环境之间拥有高速的网络连接。一旦将.NET应用容器化并推送到ECR,就为生产部署做好了准备。App Runner允许我们监听ECR,并自动部署推送到其中的新镜像。部署完成后,服务将通过HTTPS完全加密。此时,我们可以前往Cloud Shell,启动一个命令行,使用curl命令调用服务并进行测试。这代表了.NET和C#开发的下一代工作流,是除了Visual Studio之外,一个值得加入你工具箱的强大工具。

项目准备与环境设置

上一节我们介绍了整体工作流,本节中我们来看看具体的项目和环境设置。

我们将使用一个名为 NoahGift/dotnet-6-aws 的代码仓库。这是在Cloud9中运行本教程所需的一切。启动Cloud9环境后,你需要安装一些.NET 6的包,之后就可以开始部署了。

首先,我已经设置好了一个Cloud9环境。建议你设置一个性能较强的实例。需要指出的是,安装好.NET后,我可以运行 dotnet 命令。这里有一个非常简单的程序,它接受一个URL参数 /hello,并替换其中的字符串。我可以直接运行它。

如果想将其作为容器化应用运行,过程也非常直接,因为环境已经设置好了。当然,我也可以将其作为常规的.NET应用运行。让我们先运行常规版本:

dotnet run

运行后,你会看到弹出的URL。我们可以使用curl命令来测试它:

curl “http://localhost:5000/hello?name=Bob”

预期输出应为:Hello Bob。这表明应用正在正常工作。

容器化构建与本地运行

现在,我们来看看如何构建和运行容器化版本。这同样相当简单,关键在于Dockerfile。

以下是构建和运行容器化应用的核心步骤:

  1. 检查Dockerfile:该Dockerfile基于.NET 6 SDK构建。它会查看.csproj文件进行构建,并生成一个设置了端口8080的发布版本。WebService.dll将在容器化应用中暴露。
  2. 本地构建镜像:在包含Dockerfile的项目目录中,运行以下命令构建Docker镜像:
    docker build -t web-service:latest .
    
  3. 本地运行容器:镜像构建成功后,使用以下命令运行容器:
    docker run -p 8080:8080 web-service:latest
    

运行后,我们可以通过访问 http://localhost:8080/hello?name=Bob 来测试,应该会得到与之前相同的 Hello Bob 响应。

推送镜像到ECR

本地测试成功后,下一步是将镜像推送到Amazon Elastic Container Registry (ECR)。

前往AWS控制台,进入ECR服务。创建一个新的存储库(例如命名为test),过程非常简单。创建完成后,选择该存储库,点击“查看推送命令”,AWS会提供完整的推送步骤。

通常,推送命令序列如下:

# 1. 登录ECR
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account-id>.dkr.ecr.<region>.amazonaws.com
# 2. 为本地镜像打上ECR标签
docker tag web-service:latest <account-id>.dkr.ecr.<region>.amazonaws.com/test:latest
# 3. 推送镜像
docker push <account-id>.dkr.ecr.<region>.amazonaws.com/test:latest

由于Cloud9与ECR处于同一高速网络,推送速度会非常快。镜像推送成功后,就可以与团队共享,或用于ECS、App Runner等服务。

使用App Runner自动化部署

接下来,我们使用AWS App Runner来部署我们的服务。这是容器化魔力的体现。

在App Runner控制台,点击“创建服务”。配置源时,选择“容器注册表”下的“Amazon ECR”,然后浏览并选择我们刚刚推送的镜像。继续配置,你可以设置服务名称(如dotnet-app),并启用自动部署。这意味着如果构建系统推送了新版本的容器镜像,App Runner会自动部署新版本。

配置完成后,点击“创建并部署”。部署过程是自动化的,并且集成了软件开发的最佳实践,如日志、活动指标和配置管理。部署完成后,App Runner会提供一个可访问的URL。

使用Cloud Shell进行最终测试

服务部署完成后,我们需要进行最终测试。这里我们使用另一个云服务——Cloud Shell。

在Cloud Shell中,我们可以直接运行curl命令,指向App Runner提供的服务URL:

curl “https://<your-app-runner-url>/hello?name=Bob”

如果一切正常,你将再次看到 Hello Bob 的响应。这证明我们的服务已在云端成功运行。

总结

本节课中,我们一起学习了如何利用AWS的云原生服务构建完整的.NET微服务流水线。我们使用Cloud9作为云端IDE进行开发,将应用容器化后推送到ECR进行存储,通过App Runner实现自动化部署,并最终使用Cloud Shell验证服务。这个工作流提供了一个无缝、高性能的端到端开发与部署环境,无需任何本地基础设施干预。对于.NET开发者而言,尝试这套流程将极大地提升开发效率和部署灵活性。

093:AWS Copilot容器化应用命令行界面 🚀

在本节课中,我们将学习如何使用AWS Copilot命令行界面,将一个.NET Blazor应用容器化并部署到Amazon ECS服务。整个过程将涵盖从环境准备、应用创建、容器构建到一键式云端部署的完整流程。


上一节我们介绍了课程目标,本节中我们来看看具体的操作环境准备。

首先,我将启动一个AWS Cloud9开发环境。我选择Cloud9是因为它能让我自由选择实例规格,例如,如果需要,我可以选择一台拥有32个核心和大内存的机器。接着,我会安装.NET 6框架,并运行一个Blazor应用进行测试。当一切准备就绪后,我会编写一个Dockerfile,然后运行 dotnet aws deploy 命令。这个命令将自动触发一个CloudFormation流程,构建一个ECR镜像并将其推送到ECS,同时自动配置IAM角色、VPC等资源。最终,我的Blazor应用将作为任务在ECS中运行,而这一切仅需一条命令。

让我们开始操作。


现在,我已经进入了AWS Cloud9环境。我选择了一台大型机器来执行开发任务。要启动Cloud9环境,你可以访问AWS控制台,选择Cloud9并配置自己的环境。在默认配置中,我唯一建议修改的是选择一台更大的机器。目前这台机器至少有8个核心和充足的内存。

首先,为了安装.NET 6,需要确保系统包是最新的。我将执行以下命令来添加Microsoft存储库:

sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm

下一步是安装.NET 6 SDK:

sudo yum install dotnet-sdk-6.0

接着,安装ASP.NET Core运行时:

sudo yum install aspnetcore-runtime-6.0

最后,安装.NET运行时:

sudo yum install dotnet-runtime-6.0

完成这些安装后,要运行AWS部署工具,只需执行以下命令来更新工具:

dotnet tool update -g aws.deploy.tools

这个命令会检查并确保安装的是最新版本。由于该工具更新频繁,建议经常运行此命令。


上一节我们准备好了环境,本节中我们来创建并测试Blazor应用。

接下来,我将创建一个Blazor应用。使用以下命令创建一个.NET 6的Blazor Server应用:

dotnet new blazorserver -o BlazorApp -f net6.0

创建速度很快。然后,进入应用目录:

cd BlazorApp

创建完成后,要运行此应用,需要执行一个dotnet run命令,并指定在8080端口运行,以便启用预览功能:

dotnet run --urls=http://localhost:8080

此命令将在前台运行Blazor应用。为了测试它,只需点击Cloud9界面中的预览图标,然后选择“预览运行中的应用程序”。可以看到应用正在运行。我甚至可以点击页面中的计数器按钮进行交互,这证明应用运行正常。

现在,在部署之前,我可以对应用做一些修改。例如,进入 Pages/Index.razor 文件,将欢迎语修改为:

@page "/"
<h1>Hello, AWS .NET AWS Deploy!</h1>
Welcome to your new app.

修改后,可以再次通过预览功能测试更改是否生效。


上一节我们创建并修改了应用,本节中我们将其容器化。

现在开始部署。首先,需要创建一个Dockerfile来定义如何将应用容器化。在应用根目录下执行:

touch Dockerfile

然后,将以下内容粘贴到Dockerfile中:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["BlazorApp.csproj", "./"]
RUN dotnet restore "BlazorApp.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "BlazorApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "BlazorApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "BlazorApp.dll"]

这个Dockerfile使用.NET 6的SDK和运行时镜像,构建项目并暴露80和443端口。为了确保容器构建正确,可以在本地测试:

docker build -t blazorapp .
docker run -p 8080:80 blazorapp

然后通过Cloud9的预览功能访问 http://localhost:8080,确认应用在容器内运行正常。


上一节我们完成了容器构建,本节中我们使用AWS工具进行一键式部署。

最后,使用AWS部署命令进行云端部署。在应用目录下运行:

dotnet aws deploy

该工具会自动检测到Dockerfile,并提示部署选项。它会显示将“ASP.NET Core应用程序部署到使用Fargate的Amazon ECS”。这正是我们需要的。按照提示,接受默认的应用名称(如blazorapp)和集群设置。

部署过程将自动执行以下复杂步骤:

  1. 构建Docker容器镜像。
  2. 将镜像推送到Amazon ECR。
  3. 使用AWS CDK库生成CloudFormation模板。
  4. 创建ECS集群、服务、任务定义。
  5. 配置负载均衡器、IAM角色和VPC。

部署完成后,命令行会输出应用的访问端点(URL)。复制该URL并在浏览器中打开,即可看到已成功部署的Blazor应用。

此外,可以前往AWS管理控制台的ECS服务页面,查看自动创建的资源,包括运行中的任务、服务以及相关的网络和安全配置。


本节课中我们一起学习了使用AWS Copilot(通过dotnet aws deploy工具)将.NET Blazor应用容器化并部署到Amazon ECS的完整流程。我们从设置Cloud9开发环境开始,创建并测试了Blazor应用,然后编写Dockerfile定义容器,最后通过一条命令实现了从代码到云端运行的全自动部署。这个工具极大地简化了将应用部署到AWS的复杂性,是进行高效云原生开发的有力助手。

094:使用Locust进行负载测试 🚀

在本节课中,我们将学习如何使用开源的负载测试工具Locust,来验证我们的微服务在生产环境下的性能表现。负载测试是确保系统稳定性的重要环节。

概述

Locust是一个开源的负载测试工具,能够模拟数百万并发用户。它是一个非常实用的工具,可以用来测试我们的代码性能。对生产系统进行负载测试,以验证其行为能否在生产环境中复现,是开发流程中的重要部分。

准备工作

首先,我们需要一个待测试的应用程序。这里我们使用一个简单的、可以在Kubernetes上运行但也能在本地运行的微服务。

我们可以通过以下命令来运行这个应用:

python main.py

这个命令会启动我们的应用程序。

创建Locust测试文件

上一节我们启动了待测试的应用,本节中我们来看看如何为它编写负载测试。首先,我们需要创建一个Locust测试文件。

使用touch命令创建一个名为locustfile.py的文件:

touch locustfile.py

我们将在这个文件中编写我们的负载测试代码。

编写测试任务

以下是编写Locust测试脚本的核心步骤。我们将导入必要的模块并定义一个测试任务。

首先,从Locust导入HttpUsertask

from locust import HttpUser, task

我们的测试目标是调用应用程序中的一个特定接口。查看main.py文件,可以发现一个名为/fruit的路由,它会随机返回一种水果信息。

因此,我们在task装饰器下的方法中,让用户客户端访问这个/fruit端点:

class WebsiteUser(HttpUser):
    @task
    def get_fruit(self):
        self.client.get("/fruit")

运行Locust测试

编写好测试脚本后,就可以运行Locust了。只需在终端输入以下命令:

locust

这个命令会启动Locust的Web交互界面。

执行负载测试

现在,我们通过Web界面来配置并执行一次负载测试。首先,在新的终端窗口中启动我们的微服务应用,确保它在运行。

然后,在浏览器中打开Locust的Web界面(通常是 http://localhost:8089)。在界面中,我们需要配置测试参数:

  • Number of users:要模拟的用户总数,例如设置为10。
  • Spawn rate:每秒启动的用户数,例如设置为5。
  • Host:被测试应用的地址,例如 http://127.0.0.1:8000

配置完成后,点击“Start swarming”按钮开始测试。

分析测试结果

测试开始后,我们可以在Locust的Web界面上实时查看各种指标:

  • 请求数/秒:图表显示每秒处理的请求数量。
  • 响应时间:图表显示请求的平均响应时间、中位数等。
  • 失败情况:可以查看是否有请求失败或出现异常。
  • 比例:查看不同响应时间的请求分布。

这是一个非常直观的方式来构建和运行基于性能的测试。同时,我们可以看到后端应用程序正在被大量请求“冲击”。构建一个负载测试如此简单,我们没有理由不去做它。

集成到CI/CD流程

你还可以将Locust测试集成到持续集成/持续部署流程中。例如,在部署到生产环境之前,自动运行负载测试,并设定必须满足的性能指标阈值。Locust是实现自动化负载测试的绝佳工具。

总结

本节课中我们一起学习了如何使用Locust进行负载测试。我们从准备测试环境开始,逐步完成了编写测试脚本、运行测试以及分析结果的全过程。通过将负载测试集成到开发流程中,我们可以更早地发现性能瓶颈,确保应用在生产环境中的稳定性。

095:监控与日志系统

在本节课中,我们将学习如何将数据科学的思维应用于软件系统,具体探讨监控与日志在机器学习运维中的核心作用。我们将了解为什么需要监控、监控什么内容以及如何通过工具实现可视化。

概述:将监控视为软件系统的数据科学

监控与日志可以理解为软件系统的数据科学。尽管你的工作重点是机器学习运维和模型部署,但你同样需要关注所使用基础设施的“数据科学”。这意味着你需要像分析数据一样,去分析和理解你的软件系统在运行时的状态和行为。

上一节我们介绍了模型部署,本节中我们来看看如何确保部署后的系统健康、稳定运行。

监控与日志的核心概念

对于一个服务器系统,信息的来源主要有两个方面:

  1. 源代码本身:这是信息的直接来源。
  2. 日志记录:你通过代码插桩添加的日志,例如,记录执行一次特定预测所需的时间。

在监控代理方面,你需要关注一些核心指标,例如:

  • CPU 使用率
  • 磁盘 I/O
  • 内存 使用情况

以下是部署机器学习模型时需要考虑的关键监控点:

  • 预测延迟:模型进行单次预测所花费的时间。
  • 系统资源:运行模型的服务器其CPU、内存和磁盘的使用状况。
  • 错误率:模型预测失败或抛出异常的比例。

如何实现监控可视化

那么,如何查看这些监控数据呢?你可以通过 AWS CloudWatch 这类服务来实现。

  • 你可以拉起一个仪表盘,直观地查看各项指标。
  • 可以查看警报,及时响应系统异常。
  • 能够搜索特定系统的日志,进行问题排查。
  • 还能获得来自AWS CloudWatch系统的自动化洞察报告。

因此,将监控与日志视为软件系统的数据科学,是实现这一目标的最佳思维方式。

总结:可见性是系统稳定的基石

本节课中我们一起学习了监控与日志的重要性。你必须建立监控与日志体系,才能了解系统中正在发生什么,并获得系统的可见性。拥有数据科学素养是一项重要的能力,作为一名数据科学家,你需要将同样的技能应用于你所构建的软件系统本身,确保其可靠、高效地运行。

096:MLOps的SRE思维模式 🛠️

在本节课中,我们将要学习如何将站点可靠性工程师的思维模式应用于机器学习运维中。我们将探讨如何通过预见性风险发现、自动化、监控和质量控制来构建稳定、可扩展的ML系统。

概述

SRE思维模式的核心在于将软件工程的可靠性实践引入机器学习领域。这要求我们从系统设计的初始阶段就考虑自动化、监控和可重复性,以避免生产环境中的常见陷阱。

预见性风险发现

预见性风险发现是指在问题发生之前,主动识别并缓解系统中的潜在风险。在数据工程或MLOps系统中,这主要通过几个关键实践来实现。

以下是实现预见性风险发现的几个核心方面:

  • 自动化:如果缺乏自动化,组织将面临巨大风险。关键在于能否实现自动部署和自动测试。
  • 监控:如果无法监控系统状态或数据变化,就无法真正利用数据科学来洞察系统运行情况。
  • 质量控制:是否实现了自动测试或代码链接?如果不这样做,无异于在“掷骰子”,将系统稳定性寄托于运气。
  • 避免学术工具链:在当今时代,一个特别相关的问题是“学术工具链”概念。你可能构建了在学术研究中如同“神器”般好用的工具,但这些工具在进入生产环境时往往会引发问题。

DevOps与MLOps的紧密关联

上一节我们介绍了风险发现,本节中我们来看看支撑这些实践的基础。实际上,DevOps和MLOps是紧密相关的。如果没有DevOps,就无法有效地进行机器学习运维。

我们可以将其视为一个需求层次结构:

  1. 基础层:自动化基础设施即代码。这是金字塔的基石。
  2. 中间层:在稳固的基础上,才能实现数据自动化和平台自动化。
  3. 顶层:最终到达金字塔顶端,实现成熟的MLOps。

这是机器学习工程的需求层次结构。没有底层的稳固,就无法构建上层的复杂能力。

MLOps的“25法则”

理解这种层次关系后,我们需要认识到一个核心原则:MLOps不存在“银弹”。没有一个特定的哲学或工具能解决所有问题。

你必须在这所有类别中付出艰苦的努力:

  • DevOps 上付出努力。
  • 数据 上付出努力。
  • 模型 上付出努力。
  • 业务 上付出努力。

监控:软件系统的数据科学

现在,如果我们深入探讨监控,其中一个关键点是:监控就是软件系统的数据科学

如果你的公司正在实践数据科学,但却没有对软件系统进行监控(即没有对其做数据科学分析),这颇具讽刺意味。监控本质上是一个质量控制系统。

以下是构建有效质量控制系统需要考虑的方面:

  • 可重复的开发环境:能否在与生产环境完全一致的可重复环境中进行开发?例如,GitHub Codespaces 这类工具就解决了这个问题。
  • GPU访问与快速训练:能否访问GPU?能否以与生产环境相同的方式进行快速模型训练?
  • 使用最佳可用工具:是否在使用诸如 GitHub Copilot 等工具,以最高效的方式协助编写代码?使用最新技术来减少错误至关重要。
  • 基于云的系统:是否使用持续集成和持续部署等基于云的系统,来进一步提升编写代码的能力?

基于云系统的可重复性优势

基于云的系统为实现可重复性带来了多项优势:

  • 容器化构建:你可以使用容器进行构建。
  • 配置即代码:可以从一开始就构建配置。
  • 按需使用计算与存储:你可以利用云端的计算和存储资源,从而避免搭建一个与生产环境迥异的、奇怪的本地环境。

正如之前提到的,Copilot 是增强开发反馈循环的绝佳方式。通过更好的提示、学习、测试和执行,你提高了减少代码缺陷的能力,从而增强了编写高性能代码的能力。

然后,如果你观察像 GitHub Actions 这样的基于云的系统(用于持续集成和交付),它允许你将开发环境中执行的完全相同的步骤应用到生产环境。

例如,你可以使用 GitHub Actions 将一个容器推送到 Amazon ECR,然后触发一个构建到 AWS App Runner,该部署最终会提供一个 FastAPI 端点。

避免“学术数据科学工具链”

总而言之,我们需要避免的是“学术数据科学工具链”。一些在学术背景下非常有意义的事情,在生产环境中可能就不那么合理了。

以下是几种需要避免的模式:

  • Notebook作为唯一开发方式:将 Notebook 作为开发软件系统的唯一方式,因为 Notebook 本身比较脆弱,难以充分利用软件工程的最佳实践。
  • “神器”工具:使用那些在一个环境或包中安装了海量不同软件的工具。这种方式在单机上可能运行良好,但在生产环境中会带来问题。
  • “巫毒”盒子:一个很好的例子是,你桌子底下有一台“巫毒”服务器,每个人都连接它(比如在生物实验室里)。在现实世界中,你肯定不希望这样。你需要消除这类工具。

生产优先的思维模式

“生产优先”的思维模式意味着,你在开发环境中做的事情应该与在生产环境中做的事情完全一致。

  • 使用 容器
  • 使用 基于云的环境
  • 使用 持续集成和持续交付

总结

本节课中,我们一起学习了将SRE思维应用于MLOps的核心要点。我们探讨了通过自动化、监控和质量控制进行预见性风险发现的重要性,理解了DevOps是MLOps的基石,并认识了“生产优先”思维模式的价值——即使用容器、云环境和CI/CD流程来确保开发与生产环境的一致性,从而避免“学术工具链”的陷阱,构建出可靠、可扩展的机器学习系统。

097:微服务运维化实践

在本节课中,我们将学习如何将一个微服务投入实际运行,即“运维化”。我们将探讨微服务的核心特征、从代码到部署的完整流程,以及如何利用基础设施即代码和容器技术来管理多个环境。

上一节我们介绍了微服务的基本概念,本节中我们来看看如何将其投入实际运行。

微服务的核心特征

微服务的优势在代码管理工具(如Git)中得以体现。我们可以将微服务视为一段可投入实际运行的逻辑代码。

以下是微服务的一些关键特征:

  • 体量小:微服务是轻量级的。
  • 可复用代码:其代码可以被多种方式复用。

基于这些特征,一段微服务代码可以转化为多种形态:

  • 可以将其制作成一个命令行工具
  • 可以将其封装成一个代码库
  • 当然,可以将其构建成一个微服务
  • 也可以将其打包成一个Docker容器

本质上,微服务就像是一个被“运维化”并赋予了新形态的函数。

持续交付流程

接下来,我们看看代码如何通过持续交付系统或构建服务器进入生产环境。

该流程通常包含以下步骤:

  1. 代码检查:进行代码规范检查。
  2. 测试:运行各类测试。
  3. 编译:编译代码。
  4. 推送至容器仓库:将构建好的容器镜像推送到仓库。
  5. 基础设施即代码部署:最后通过基础设施即代码的方式完成部署。

多环境管理与自动化

通过结合使用基础设施即代码容器技术,我们可以轻松创建和管理任意数量的环境。

例如,您可以创建以下环境:

  • 开发环境
  • 预发布环境
  • 生产环境
  • 负载测试环境

系统可以根据代码被部署到的不同环境,执行相应的自动化操作。

预发布环境的监控与验证

以预发布环境为例,我们可以实施一套监控与验证流程。以下是具体步骤:

  1. 部署微服务:将微服务部署到预发布环境。
  2. 监控健康指标:微服务会暴露健康指标,如CPU使用率、内存占用、请求延迟等。
  3. 集成监控系统:这些指标被收集到监控系统中,例如Prometheus或AWS的CloudWatch
  4. 性能验证:此步骤旨在验证服务的实际表现是否符合预期。

一旦微服务在预发布环境中通过所有验证,您就可以轻松地将其合并到新的分支,并直接部署到生产环境。

本节课中我们一起学习了微服务运维化的完整流程。总而言之,微服务最简洁的解释就是:一段您投入实际运行的逻辑代码。通过标准化的构建、部署和验证流程,我们可以确保微服务能够可靠、高效地服务于不同环境。

098:构建自动化工作流

在本节课中,我们将学习如何为微服务项目设置一个持续集成生态系统。我们将从最重要的第一步——项目结构开始,并了解如何通过自动化工具确保代码质量。

概述

持续集成的核心是,每当开发者将代码变更推送到基于Git的代码仓库时,系统能够自动执行测试、代码规范检查和格式化。这通过一个Makefile来实现,它定义了本地可执行的命令。同时,一个构建服务器(机器人)会复制这些操作,持续检查代码的规范性、格式和测试结果,为后续部署做好准备。建立本地的持续集成环境,是项目能够顺利进入生产阶段的关键。

上一节我们介绍了持续集成的核心概念,本节中我们来看看如何在实践中通过一个GitHub项目来实现它。

项目结构解析

一个为持续集成和持续交付做好充分准备的项目,应包含以下关键组件。

以下是项目仓库中的主要组成部分:

  • .github/workflows 目录:这是构建系统的配置所在。本例中使用的是GitHub Actions,但你也可以使用Jenkins、AWS Code Build等其他系统。这里的配置文件会指示构建系统如何测试和验证代码。
  • main.yml 文件:这是工作流配置文件。它规定在每次代码推送时,系统会在一个Ubuntu虚拟机上启动,使用Python 3.8,并依次执行 make installmake lintmake testmake format 命令。这种结构是所有持续集成项目的推荐做法。
  • 代码环境文件
    • README.md 文件:项目说明文档。
    • main.py 文件:一个简单的示例代码文件,例如实现两数相加。
    • test_main.py 文件:用于测试 main.py 中代码的测试文件。
    • requirements.txt 文件:列出了项目依赖的、带有版本号的Python包。这确保了开发环境与构建系统环境的一致性,使项目具有可复现性。
  • Makefile 文件:这是自动化命令的“食谱”。它定义了如 make installmake testmake formatmake lint 等一系列命令(recipe),开发者只需运行简单的 make 命令即可触发复杂的操作流程。

了解了项目结构后,接下来我们看看如何在真实环境中使用它。我们将利用GitHub Codespaces这个云端开发环境来进行演示。

实践演练:在云端环境中工作

我们进入了GitHub Codespaces环境,左侧是项目代码,右侧打开了终端。我已经预先创建了一个虚拟环境。现在,我们来运行 make all 命令。

make all

这个命令会依次执行安装依赖、代码检查、运行测试等步骤。如果一切正常,我们将收到所有操作成功的反馈,形成一个高效的正向循环。

那么,如果代码有问题会怎样?让我们引入一个“小bug”:将一个变量赋值给它自身。这不会导致代码立即崩溃,但可能在未来引发问题。

当我们再次运行 make lint 时,代码检查工具会捕获到这个潜在问题,并给出警告或错误信息。这展示了代码检查在发现潜在缺陷方面的能力。

现在,我们将这个有问题的变更推送到远程仓库。

git add .
git commit -m "Introduce a linting issue for demo"
git push

推送完成后,我们可以观察持续集成系统的反应。这就是持续集成系统的优势:它是一个时刻监视代码的“机器人”,能自动发现安装、代码规范、测试等方面的问题。果然,由于我们引入了代码规范问题,这次构建失败了。

构建失败后我们该怎么办?幸运的是,修复非常简单。我们甚至不需要打开本地的开发环境,可以直接在GitHub的网页界面上编辑有问题的文件,删除那两行有问题的代码,然后提交修复。

提交后,构建服务器会自动重新运行任务。我们可以看到它正在设置环境、安装依赖,然后再次执行代码检查和格式化。最终,所有检查都通过了。

总结

本节课中我们一起学习了为微服务设置持续集成系统的完整流程。我们了解了核心的项目结构,包括 Makefile.github/workflows 配置文件的作用,并实践了从本地开发、代码检查、问题发现到在线修复、自动验证的完整工作流。这个过程是任何进行微服务开发、命令行工具开发乃至一般Python软件开发的项目都应该具备的,它能显著提升代码质量和开发效率。

099:什么是持续交付 🚀

在本节课中,我们将学习持续交付的核心概念,并了解如何利用现代云原生工具构建一个自动化的软件交付工作流。


上一节我们介绍了持续交付的基本理念,本节中我们来看看一个具体的持续交付工作流是如何运作的。我们将使用最新的云原生生态系统工具来构建这个流程。

首先,开发工作通常在云端环境中进行。例如,AWS的Cloud 9或Azure平台的GitHub Codespaces。使用这些云原生环境的原因是,它们能让你使用与未来生产环境一致的开发工具,从而构建出一个与生产环境高度相似的开发环境。

在构建过程中,你不仅会推送软件代码,还会推送“基础设施即代码”。基础设施即代码允许你定义云环境或Kubernetes环境中每一个组件的配置。值得注意的是,当你推送变更时,构建系统会自动测试你的代码、合并代码,然后这个构建版本会自动进入“资源供给”阶段。

基础设施即代码的强大之处在于它是幂等的。这意味着,它只在必要时才做出变更,并且始终确保环境状态保持一致。例如,如果你最初创建了基础设施,在进行第二次构建时,它不会重复创建,因为它会检测到(比如)某个S3存储桶已经存在,因此无需再次创建。

同样地,如果你修改了基础设施即代码的配置,比如做一个小改动,系统会识别出差异,并为你创建一个新的存储桶。最后,如果需要清理资源,使用基础设施即代码也能轻松完成。

此外,你还可以执行各种强大的操作。例如,你可以选择不执行删除操作,而是创建一个全新的基础设施。你可以构建一个特定的预发布环境,用于进行负载测试。同样地,你可以复制代码和基础设施即代码的配置,再创建一个生产环境

这种利用代码来定义系统、并实现幂等变更的理念,是持续交付的重要组成部分。它使你能够持续地将变更推送到新环境。这并不意味着在没有人工干预的情况下,变更总会直接进入生产环境,但它确实允许你将变更推送到多个不同的环境。这正是持续交付的关键概念。


本节课中我们一起学习了持续交付工作流的核心组成部分,包括使用云原生开发环境、基础设施即代码的幂等性,以及如何通过自动化流程将代码变更安全、一致地推送到多个环境(如预发布和生产环境)。

100:数据可视化入门 📊

在本节课中,我们将要学习数据可视化的基础步骤和核心概念。我们将探讨如何从明确目标开始,到选择正确的图表类型,再到优化可视化效果,最终有效地讲述数据背后的故事。


明确故事与收集数据

首先,你需要思考你想要讲述的故事。为了做到这一点,你需要收集一些数据。

以下是开始前需要考虑的几个关键问题:

  • 数据从哪里获取?
  • 手头的数据是否有用?
  • 数据是否包含你需要的信息?
  • 数据是否有缺失?
  • 你想用数据讲述什么故事?
  • 你期望得到什么结果?

在开始制作可视化图表之前,你需要考虑期望的结果,因为这能引导你选择正确的可视化方式。


优化与提炼可视化

当你创建了一个可视化图表后,你需要考虑它是否有效地讲述了你想要的故事。

以下是优化可视化的几个方法:

  • 调整某些方面以突出特定要点。
  • 添加注释来辅助说明。
  • 更改配色方案以强调图表的某些部分。

一个能真正清理你数据的概念是“数据墨水比”,即你的可视化图表中有多少部分是讲述故事所必需的,有多少是背景信息。通常,如果可能,你应该弱化或移除背景信息。

遵循这个过程——思考要讲述的故事、收集数据、构思正确的可视化方式,然后专注于确保你的可视化在讲述一个故事——将引导你制作出引人注目的可视化图表。


根据数据类型选择图表

你需要考虑的一个因素是所拥有的数据类型。如果你有数值型数据,你将需要制作与分类数据不同的可视化图表。

让我们看一些用数值数据讲故事的例子。

线图:如果你有随时间变化的数据,用线图来可视化是一个很好的方法。

直方图:如果你只有一列数据,并且想理解它,你可能需要查看其分布。可视化和理解数据分布的一个好方法是使用直方图。

散点图:如果你有两列不同的数据,查看它们之间关系的常用方法是使用散点图。这可以让你快速可视化关系是正向、负向,还是不存在关系。

理解你拥有的数据类型可以帮助你选择正确的图表。

对于分类数据,你也需要确保使用正确的图表。通常,当我使用分类数据时,我关注的是类别的计数,而条形图是理解这一点的好方法。这是我处理分类数据的首选图表。有时,你甚至可能需要对条形图进行分面处理,如果你有多个类别需要跨多个维度查看。


通过数据摘要快速理解

另一种理解数据的常见方法是进行总结。我喜欢告诉我的学生,你的老板通常不想知道琐碎的细节。一般来说,他们想要一个快速的故事,而获取快速故事的好方法就是总结数据。

以下是几种常见的数据摘要方法:

集中趋势:例如,你可能想理解数据的集中趋势。实现这一点的几种方法是计算均值或中位数。通过理解这个单一的数据点,你通常可以理解大量数据。

离散程度:如果你想理解数据的离散程度,用一个单一值来理解的方法是查看标准差之类的指标。

关系:如果你有多列数据,你可能需要考虑它们之间的关系。这也可以通过相关性来总结。

比率:如果你想查看两列数据之间的关系或它们之间的百分比关系,可以考虑使用比率。

通过总结你的数据,你将能够更快地讲述你的故事,并在叙事中更加有效。


本节课中,我们一起学习了数据可视化的完整流程:从明确目标和收集数据开始,根据数据类型(数值型或分类型)选择合适的图表(如线图、直方图、散点图、条形图),并通过优化“数据墨水比”来提升图表效果。最后,我们还探讨了如何使用均值、中位数、标准差和相关性等统计量来快速总结数据,从而更高效地传达核心信息。掌握这些基础步骤,是迈向有效数据沟通的第一步。

101:Excel可视化简介 📊

在本节中,我们将学习如何使用Excel创建数据可视化图表。Excel是一款广泛使用的工具,它能快速、便捷地完成许多任务。

上一节我们介绍了数据可视化的基本概念,本节中我们来看看如何在Excel中具体实现。

概述

Excel是一个强大的工具,因为它被普遍使用,并且能让许多操作变得快速简单。然而,需要指出的是,从长期可维护性的角度来看,快速和简单有时并非最佳选择。作为一名程序员,我个人更倾向于使用代码(例如Pandas库)来处理数据,因为代码可以编写测试、部署到生产系统,具有更好的长期可维护性。尽管如此,掌握Excel仍然非常重要,因为很多人都在使用它,并且它能非常轻松地完成许多特定任务。Excel的设计优化了某些操作的便捷性。

核心步骤

以下是使用Excel创建图表的基本流程。

  1. 准备数据
    确保你的数据已整理在Excel工作表中,通常数据应排列在行和列中,并包含清晰的标题。

  2. 选择数据
    用鼠标拖拽选中你想要可视化的数据区域,包括行标题和列标题。

  3. 插入图表
    转到“插入”选项卡,从“图表”组中选择你需要的图表类型,例如柱形图、折线图或饼图。

  4. 自定义图表
    使用“图表设计”和“格式”选项卡来调整图表的样式、颜色、标题、坐标轴标签等元素,使其更清晰美观。

  5. 分析图表
    观察生成的图表,解读数据所展现的趋势、比较或分布情况。

总结

本节课中我们一起学习了在Excel中创建数据可视化的基本方法。我们了解到Excel因其普及性和易用性而成为快速探索和展示数据的有效工具。同时,我们也认识到对于需要长期维护和自动化的复杂任务,编程工具可能是更优的选择。掌握多种工具,并能根据具体场景选择最合适的一种,是数据工程实践中的重要能力。

102:在Excel中创建折线图 📈

在本节课程中,我们将学习如何使用Excel创建折线图。我们将使用“Dirty Devil”数据集,绘制一条展示多年间每秒立方英尺流量变化的折线图。

准备数据与创建数据透视表

首先,我已经在Excel中加载了数据集。我们的目标是查看每年每秒立方英尺流量的变化趋势。由于数据集中包含多个年份的数据,我们需要先创建一个数据透视表来汇总这些信息。

以下是创建数据透视表和图表的步骤:

  1. 转到Excel的“插入”选项卡。
  2. 点击“数据透视表和数据透视图”按钮,以便直接创建数据透视图。

配置数据透视图字段

创建数据透视图后,右侧会出现字段列表。我们需要将相应的字段拖放到指定区域来构建图表。

以下是需要配置的字段:

  • 图例(系列):将“Years”(年份)字段拖入此处。
  • :将“Cubic Feet Per Second”(每秒立方英尺)字段拖入此处。

此时,图表会显示每年每秒立方英尺流量的总和。但为了创建折线图,我们还需要一个维度来展示时间序列的变化。

添加类别轴并更改图表类型

上一节我们配置了基本的数据汇总,本节我们来看看如何将其转换为折线图。关键在于将“Day of the Year”(一年中的第几天)字段拖入“轴(类别)”区域。

现在图表显示了数据,但可能因为存在一些异常值而难以阅读。我们可以通过调整坐标轴范围来聚焦主要数据。

调整坐标轴以优化视图

为了使图表更清晰,我们可以调整Y轴(数值轴)的显示范围。

以下是具体操作步骤:

  1. 单击图表中的Y轴。
  2. 在右侧的“设置坐标轴格式”窗格中,找到“边界”选项。
  3. 将“最大值”修改为一个更合适的值,例如 1000,以排除过高异常值的干扰。

调整后,图表视图得到了改善。但当前的图表类型看起来更像是柱形图,我们需要将其改为折线图。

最终完成折线图

最后一步是将图表类型更改为折线图。

  1. 在图表上右键单击。
  2. 选择“更改系列图表类型”。
  3. 在弹出的窗口中,选择“折线图”,然后点击“确定”。

完成后的折线图清晰地展示了每年内,每日每秒立方英尺流量的变化趋势。

这与我们使用Pandas时的情况类似,都是先对数据进行聚合(按年份),然后可视化每个年份内每日的流量值。

总结

本节课中,我们一起学习了在Excel中创建折线图的完整流程。我们首先通过插入数据透视图来汇总数据,然后通过配置字段(年份作为图例、日序作为类别、流量作为值)来构建图表基础,接着通过调整坐标轴范围优化了数据视图,最后将图表类型更改为折线图,从而直观地展示了时间序列数据的变化趋势。

103:在Excel中创建直方图 📊

在本节课中,我们将学习如何使用Excel软件,基于一组数据来创建直方图。直方图是一种强大的图表,能够直观地展示数据的分布情况,帮助我们快速识别数据的集中趋势和异常值。

上一节我们介绍了数据可视化的基本概念,本节中我们来看看如何利用Excel这一常用工具来制作直方图。

创建直方图

我们将以“水位计高度”这组数据为例,演示创建直方图的完整步骤。

以下是创建直方图的具体操作流程:

  1. 选择数据:首先,用鼠标选中包含“水位计高度”数据的整列。
  2. 插入图表:接着,点击Excel顶部菜单栏的“插入”选项卡。
  3. 选择图表类型:在“图表”区域,你可以直接点击“统计图表”下的“直方图”图标。或者,你也可以点击“推荐的图表”按钮。

点击“推荐的图表”后,Excel会根据所选数据提供多种图表建议。对于当前的数据,我们依然选择直方图作为查看数据分布的最佳推荐图表。

解读直方图

生成的直方图能够清晰地展示数据的分布特征。

从图中我们可以看出,以“立方英尺每秒”为单位的水流量,其最常见的数值范围集中在3.1到3.4之间。同时,我们也能直观地发现,在数值15附近存在一些明显的异常值

本节课中我们一起学习了在Excel中创建和解读直方图的方法。通过这个简单的工具,我们可以快速将一列数据转化为直观的分布图表,从而有效地分析数据的集中区域并识别出可能的异常点。

104:在Excel中创建散点图 📊

在本节课程中,我们将学习如何在Excel中创建一个散点图。我们将使用“立方英尺每秒”和“测量高度”这两列数据,通过调整图表设置来更清晰地展示数据关系,并识别其中的异常值。

概述

我们将从复制和调整数据列的顺序开始,以确保正确的数据被分配到图表的X轴和Y轴。接着,我们会插入一个基本的散点图,并通过格式化坐标轴来优化图表的可读性,特别是处理数据中的异常值。

数据准备与图表创建

首先,我们需要准备数据。目标是创建一个散点图,其中X轴代表“测量高度”,Y轴代表“立方英尺每秒”。

以下是操作步骤:

  1. 选择“立方英尺每秒”和“测量高度”这两列数据。
  2. 复制这两列数据,并将它们粘贴到工作表的另一个区域。
  3. 调整列的顺序,确保“测量高度”这一列位于第一列,因为我们将把它用作X轴的数据。

完成数据准备后,我们就可以创建图表了。

  1. 选中调整好顺序的两列数据。
  2. 转到Excel的“插入”选项卡。
  3. 在图表区域选择“散点图”。

这样,一个基本的散点图就生成了。

优化图表与解读数据

上一节我们创建了基本的散点图,本节中我们来看看如何通过调整坐标轴来优化它,并解读图表揭示的信息。

生成的初始图表中可能包含一些异常值,这些值会使大部分数据点聚集在图表的一个小区域内,不利于观察主要的数据趋势。

为了更清晰地展示核心数据分布,我们需要调整Y轴(值轴)的范围。操作方法是:右键点击Y轴,选择“设置坐标轴格式”。在弹出的窗格中,将最大值修改为一个更合理的数值,例如 1000

调整坐标轴范围后,图表讲述了一个与包含异常值时完全不同的数据故事。数据点的分布模式变得更加清晰可见。

此外,图表还清晰地揭示了一些有趣的现象。例如,在X轴(测量高度)值约为 3.4 的位置,数据点形成了一条垂直的线。这个散点图将这一现象突出地展示出来,这可能是需要进一步深入分析的数据点。

总结

本节课中我们一起学习了在Excel中创建和优化散点图的完整流程。我们首先通过调整数据列顺序来正确分配坐标轴,然后插入散点图。接着,通过格式化坐标轴、调整最大值来排除异常值的干扰,从而让主要的数据关系和潜在问题(如特定测量高度下的数据聚集)得以清晰呈现。这个过程是进行初步数据探索和可视化的有效方法。

105:在Excel中创建条形图 📊

在本节课程中,我们将学习如何在Excel中创建一个条形图,用于可视化每月流量的中位数(立方英尺/秒)。我们将使用数据透视表功能来快速生成图表。

上一节我们介绍了数据的基本处理,本节中我们来看看如何利用Excel的图表功能进行数据可视化。


首先,我们需要准备用于创建图表的数据。在本例中,我们将使用每月流量数据。

我将按住Shift键,选择我需要的列数据。

选择数据后,点击菜单栏的“数据透视表”功能。由于我们已经选定了数据范围,Excel会自动将其作为数据源,并在界面右侧弹出字段选择器。

接下来,我们需要确定各个字段应放置在数据透视表的哪个区域。

因为我们希望按月份对数据进行分类,所以将“Month”(月份)字段拖放至“行”(或“分类”)区域。

我们想要展示的值是“Cubic Feet per Second”(立方英尺/秒)。将此字段拖放至“值”区域。

此时,图表默认显示的是该值的总和。如果我们想将其改为中位数,可以进行以下操作。

点击值区域的字段,选择“值字段设置”。

在弹出的对话框中,我们可以搜索并选择不同的汇总方式。遗憾的是,Excel数据透视表默认的汇总选项中没有“中位数”。

最接近的选项是“平均值”。因此,我们点击选择“平均值”。

完成设置后,条形图便生成了。从图表中可以清晰地看出,十月份的平均立方英尺/秒流量最高。

同样明显的是,七月份的流量是最低的。


以下是创建条形图的关键步骤总结:

  1. 选择数据:按住Shift键,选择包含月份和流量值的所有相关数据列。
  2. 插入数据透视表:在菜单栏选择“插入”->“数据透视表”,使用选定的数据范围。
  3. 配置字段
    • 将“月份”字段拖至“行”区域,作为分类依据。
    • 将“流量值”字段拖至“值”区域,作为计算数值。
  4. 更改计算方式:点击值字段,在“值字段设置”中将计算方式从“求和”改为“平均值”(因无“中位数”选项)。
  5. 生成图表:Excel会自动根据数据透视表生成对应的条形图。

本节课中我们一起学习了在Excel中利用数据透视表创建条形图的方法。我们掌握了从选择数据、配置字段到更改值计算方式的完整流程,并成功生成了展示月平均流量变化的可视化图表。通过这个图表,我们可以直观地比较不同月份的数据差异。

106:最小化可视化中的杂乱元素

在本节课中,我们将学习如何通过减少图表中的杂乱元素,使数据故事更加清晰和有力。核心目标是识别并移除所有分散注意力的元素,让观众能立刻聚焦于你想传达的关键信息。

避免图表杂乱

创建图表时,我们的目标之一是避免杂乱。实现这一目标的方法之一是,在审视图表时,考虑图表上的每一个元素,并问自己:这个元素是在增强故事性,还是在削弱它?你想讲述的故事是什么,当前元素是在贡献还是削弱这个故事?

接下来,我将展示一个来自Dark Horse Analytics的常见动图,它能清晰地说明这一点。

简化过程示例

以下是图表简化的一个典型过程。初始图表的设计可能有些夸张,但你可以看到,他们只是考虑了图表上的每个点,并逐步将其移除。

这个过程包括:去掉不必要的元素、淡化次要信息、减少其视觉冲击力、消除任何特殊效果。最终使一切变得非常简单,然后将观众的注意力引导到我们想要强调的地方。在这个例子中,他们似乎想将注意力引向“培根”及其对应的卡路里数值。

对比初始图表和最终图表,你会发现两者差异显著,而你的视线会直接被“培根”所吸引。

核心原则与应用

上述动画中包含了许多步骤。虽然初始图表可能有些极端,但核心原则是成立的:你希望你的图表能讲述一个故事,并且需要移除其中的干扰因素。你越是能清晰地讲述并聚焦于这个故事,你的图表效果就越好。

因此,建议你对自己的图表也进行这样的审视和简化过程。我不会在这里使用我们所有的不同工具来演示清理图表的每一个步骤。但许多可视化工具都提供了操作选项,用于调整和改变图表的外观、填充、颜色等,以达到清理和优化的目的。

作为一名数据故事的讲述者,请确保你的图表具有吸引力,并能准确传达你想要讲述的故事。

总结

本节课中,我们一起学习了如何通过最小化图表中的杂乱元素来提升数据可视化的效果。关键在于识别并移除所有与核心故事无关的干扰项,使用简洁的设计将观众的注意力直接引导至关键数据点上。记住,一个有效的图表应该像一个好故事一样,焦点明确、叙述清晰。

107:Sheets可视化简介 📊

在本节课中,我们将学习如何使用Google Sheets进行数据可视化。Google Sheets是一款基于网页的电子表格工具,它拥有与Excel相似的大量功能。我们将看到,之前在Excel中创建的大部分图表,同样可以在Google Sheets中实现。

什么是Google Sheets? 📈

上一节我们介绍了数据可视化的基本概念,本节中我们来看看具体的工具。Google Sheets是一个基于网页的电子表格应用程序。它具备Excel的许多核心功能,例如公式计算、数据排序和筛选,以及强大的图表创建能力。

在Sheets中创建图表

了解了Google Sheets的基本性质后,我们来看看如何用它来绘图。以下是在Google Sheets中创建图表的基本步骤:

  1. 准备数据:首先,在表格中输入或导入你想要可视化的数据。
  2. 选择数据范围:用鼠标拖拽选中包含数据的单元格区域。
  3. 插入图表:点击菜单栏的“插入” -> “图表”。
  4. 选择图表类型:在右侧打开的“图表编辑器”中,从“图表类型”下拉菜单中选择合适的图表,如折线图、柱状图或饼图。
  5. 自定义图表:你可以在“图表编辑器”中进一步调整图表的标题、坐标轴、图例和颜色等属性。

核心功能与公式

Google Sheets的核心功能之一是其公式系统,它允许你对数据进行动态计算。例如,计算一列数据的平均值可以使用 AVERAGE 函数:

=AVERAGE(B2:B100)

这个公式会计算B2到B100单元格范围内所有数值的平均值。类似的函数还有 SUM(求和)、COUNT(计数)等,它们为数据分析和后续的可视化提供了基础。

与Excel的对比

我们已经介绍了在Sheets中绘图的方法,现在可以将其与Excel进行简单对比。两者在创建图表的基本逻辑上非常相似,都遵循“选择数据 -> 插入图表 -> 自定义样式”的流程。主要的区别在于操作环境和协作功能:Google Sheets完全在线,支持多人实时协作编辑;而Excel则主要是一款本地桌面软件。

总结

本节课中我们一起学习了Google Sheets在数据可视化中的应用。我们了解到Google Sheets是一款功能强大的在线电子表格工具,可以用于创建多种类型的图表。其操作流程与Excel类似,但更侧重于便捷的在线访问与团队协作。掌握Sheets的基础图表功能,是进行快速、简单数据可视化的有效途径。

108:在Google Sheets中创建折线图 📈

在本节课中,我们将学习如何在Google Sheets中创建折线图,以可视化每年每日的立方英尺每秒流量数据。我们将通过创建数据透视表来整理数据,并据此生成图表。

概述

我们将使用Google Sheets的数据透视功能来汇总数据,然后基于汇总结果创建折线图。目标是让每年的流量数据成为图表中的一条独立折线。

创建数据透视表

首先,我们需要创建一个数据透视表来整理原始数据。数据透视表能帮助我们按年份和一年中的天数来汇总流量值。

以下是创建数据透视表的步骤:

  1. 在Google Sheets中,点击菜单栏的 插入
  2. 从下拉菜单中选择 数据透视表
  3. 在弹出的对话框中,选择 新工作表 作为数据透视表的放置位置。

配置数据透视表字段

创建数据透视表后,我们需要配置其行、列和值字段,以正确汇总数据。

上一节我们创建了数据透视表,本节中我们来看看如何配置字段以生成我们需要的汇总视图。

以下是配置数据透视表的具体字段:

  • : 将 年份 字段拖入列区域。这样,每个年份将成为图表中的一条独立折线。
  • : 将 立方英尺每秒 字段拖入值区域。汇总方式选择 求和,以计算每日流量的总和。
  • : 将 一年中的天数 字段拖入行区域。这将在X轴上按时间顺序排列数据点。

配置完成后,数据透视表将按天显示每年的流量总和。

生成折线图

数据整理完毕后,我们可以基于数据透视表的结果创建折线图。

现在我们已经有了整理好的数据,接下来看看如何将其转换为直观的折线图。

以下是生成折线图的步骤:

  1. 在数据透视表中,选中所有代表年份数据的列。注意:请排除第一列(行标签列)和最后的“总计”列。可以按住 Shift 键进行多选。
  2. 再次点击菜单栏的 插入,然后选择 图表
  3. Google Sheets会自动根据选中的数据生成一个图表。

调整图表坐标轴

生成的初始图表可能因为数据中的极值(异常值)而导致比例尺不合适,使得主要数据趋势不明显。我们需要调整Y轴的范围。

图表生成后,为了使数据趋势更清晰,我们需要对坐标轴进行一些调整。

以下是调整Y轴范围的步骤:

  1. 在图表上,右键点击Y轴(垂直轴)。
  2. 从右键菜单中选择 设置坐标轴
  3. 在右侧出现的编辑器中,找到 垂直轴 设置部分。
  4. 最小值 手动设置为 0
  5. 最大值 手动设置为 1000

经过调整,图表将能更清晰地展示每年每日立方英尺每秒流量的变化趋势。

总结

本节课中我们一起学习了在Google Sheets中创建折线图的完整流程。我们首先通过插入数据透视表来汇总和整理数据,然后基于整理好的数据插入图表,最后通过调整Y轴范围来优化图表的可读性。这个方法可以有效地将时间序列数据按不同类别(如年份)进行可视化对比。

109:在Sheets中创建直方图 📊

在本节课程中,我们将学习如何使用Google Sheets来创建一个直方图。直方图是一种用于展示数据分布情况的图表,特别适合观察连续数据的频率分布。

上一节我们介绍了数据的基本处理,本节中我们来看看如何将数据可视化,直观地理解其分布特征。

我们将以“水位高度”这一列数据为例,创建其直方图。

以下是创建直方图的具体步骤:

  1. 首先,选中包含“水位高度”数据的整列。
  2. 接着,点击菜单栏中的“插入”选项。
  3. 在下拉菜单中,选择“图表”。

此时,Sheets会自动生成一个默认的图表。但这个图表可能不是我们需要的类型。

我们需要对图表类型进行调整。在屏幕右侧会弹出“图表编辑器”面板。

在“图表编辑器”中,找到“图表类型”的设置项。默认的图表类型可能是“柱形图”。

我们需要向下滚动图表类型列表,找到并点击“直方图”这一选项。

完成以上步骤后,直方图就成功创建了。这个图表再次向我们展示了与在Excel中观察到的相同结论:每秒立方英尺流量数据中最常见的数值集中在3.4左右。

本节课中我们一起学习了在Google Sheets中创建直方图的方法。通过将数据可视化,我们可以更直观、快速地洞察数据的集中趋势和分布形态,这是数据分析中非常基础且重要的一步。

110:在Google Sheets中创建散点图 📊

在本节课程中,我们将学习如何在Google Sheets中创建散点图,以可视化两个变量之间的关系。我们将使用“流量(立方英尺/秒)”与“水位高度”的数据作为示例。

概述

散点图是一种强大的数据可视化工具,用于展示两个连续变量之间的关系。通过观察数据点在图表上的分布,我们可以识别出趋势、相关性或异常值。本节将引导您完成在Google Sheets中创建和自定义散点图的完整步骤。

创建散点图

首先,我们需要在数据表中插入一个图表。以下是具体操作步骤。

以下是创建图表的基本步骤:

  1. 在Google Sheets菜单栏中,点击 “插入”
  2. 在下拉菜单中选择 “图表”
  3. 此时,工作表右侧会弹出图表编辑器,并且图表区域可能会显示“无数据”的提示,这属于正常情况。

配置图表类型与数据

上一节我们插入了图表,本节中我们来看看如何将其设置为散点图并绑定数据。

在右侧的图表编辑器中,我们需要进行以下配置:

  • “图表类型” 下拉菜单中,选择 “散点图”
  • 选择后,编辑器会显示 “数据范围”“X轴”“序列” 等配置选项。

我们主要关注 “X轴”“序列” 的设置。首先配置X轴数据。

  • 点击 “X轴” 下方的数据范围选择框。
  • 在弹出的窗口中,选择代表 “水位高度” 的数据列。

接下来,我们需要为图表添加数据序列,即Y轴的数据。

  • 在图表编辑器的 “序列” 部分,点击数据范围选择框。
  • 在弹出的窗口中,选择代表 “流量(立方英尺/秒)” 的数据列,然后点击 “确定”

完成以上步骤后,一个基础的散点图就生成了。

自定义图表以优化视图

基础图表已经创建完成,但为了更清晰地观察核心数据分布,我们通常需要调整坐标轴范围,以排除极端异常值的干扰。

观察初始生成的散点图,可能会发现一些点因数值过大而远离主体,使得主要数据点聚集在图表左下角,难以分析。这时,我们可以通过调整垂直轴(Y轴)的刻度范围来改善视图。

  • 在图表编辑器中,找到 “自定义” 选项卡下的 “垂直轴” 设置。
  • 手动修改 “最小值”“最大值”,将Y轴的显示范围限定在主要数据分布的区间内。

调整后,数据点会更均匀地分布在图表区域内,关系趋势也变得一目了然。此时,图表中可能更明显地出现一些垂直排列的数据点,这通常暗示着这些“流量”值在相同的“水位高度”下出现了多个不同的读数,表明数据可能存在需要进一步检查的异常或特殊情况。

总结

本节课中我们一起学习了在Google Sheets中创建散点图的全过程。我们首先通过 “插入”->“图表” 创建图表,然后将其类型设置为散点图,并分别指定X轴和序列(Y轴)对应的数据列。最后,为了更有效地展示数据,我们介绍了如何通过调整垂直轴的数值范围来自定义图表视图,从而聚焦于核心数据分布并识别潜在问题。掌握这些步骤,您就能利用散点图初步探索数据集中的变量关系了。

111:在Google Sheets中创建条形图 📊

在本节课中,我们将学习如何在Google Sheets中创建一个条形图,用于可视化每月流量的中位数(以立方英尺/秒为单位)。我们将从插入图表开始,逐步配置图表类型、数据系列和聚合方式,最终得到一个清晰展示月度数据趋势的图表。

概述

我们将使用Google Sheets的图表功能,基于月份和流量数据创建一个柱状图(即条形图)。核心步骤包括选择正确的图表类型、指定X轴和系列数据,并将默认的求和聚合方式更改为中位数计算。

创建图表

首先,我们需要在数据表中插入一个图表。以下是具体步骤。

  1. 在菜单栏中点击“插入”,然后选择“图表”。
  2. 在右侧打开的“图表编辑器”中,默认图表类型通常是“柱状图”,这正是我们需要的条形图类型。

配置X轴与数据系列

上一节我们插入了图表,本节中我们来看看如何为其配置数据。X轴将用于显示月份,而数据系列则代表流量值。

我们需要指定哪个数据列作为X轴,哪个作为数据系列(Y轴的值)。

  • X轴:我们选择“月份”列。这会将数据按月份分组。
  • 数据系列:我们选择“CFS”(立方英尺/秒)列。这将是图表中柱子的高度所代表的值。

应用聚合计算

在配置好基本数据后,我们需要对数据系列进行聚合计算。默认情况下,Google Sheets会对同一月份的所有CFS值进行求和,但我们需要的是中位数。

  1. 在“图表编辑器”的“设置”标签页下,找到“系列”部分。
  2. 选中“CFS”系列,并勾选“聚合”复选框。
  3. 将聚合类型从默认的“求和”更改为“中位数”。

完成此操作后,图表将显示每个月CFS值的中位数,从而消除了异常值的影响,更能反映典型情况。

调整X轴顺序

目前,我们的图表有一个小问题:X轴(月份)的顺序不是从1月(1)开始,而是从数据中第一个出现的月份(本例中是5月)开始。

这是因为Google Sheets会根据数据中实际存在的月份来动态生成X轴,并且在此图表类型中,无法手动将轴顺序设置为固定的1到12月。虽然可以反转现有顺序,但无法强制从特定月份开始。这是使用此类工具时需要注意的一个特性。

总结

本节课中,我们一起学习了在Google Sheets中创建条形图的全过程。我们掌握了如何插入柱状图、配置月份为X轴、设置流量数据为系列,并将聚合方式从求和改为中位数。最后,我们了解了图表在X轴排序上的一个限制。通过这个直观的条形图,我们可以轻松比较不同月份间的流量中位数差异。

112:优化可视化颜色方案 🎨

在本节中,我们将探讨数据可视化中的颜色选择策略。颜色是传达信息、突出重点和增强图表可读性的关键工具。我们将学习如何避免常见的颜色使用误区,并选择适合不同数据类型的配色方案。

颜色选择的重要性

在之前的示例中,我们并未过多使用颜色。然而,选择颜色时,需要考虑你想讲述的故事。例如,我们之前绘制的“Dirty Devil”河年径流量(立方英尺/秒)折线图就有些混乱。图中使用了多种颜色,导致难以理解图表内容。

通常,当折线图包含过多线条时,人们会称之为“意大利面条图”,因为信息过于繁杂,难以辨别重点。

突出重点线条

因此,我们通常需要聚焦于单条线条。这条线可能是最小值、最大值,也可能是异常值或中间值。以下是一个绘制各国预期寿命的示例,它看起来就像一个杂乱的“意大利面条图”。

我们可以采取的方法是淡化其他所有线条的颜色,只将其中一条线条高亮显示。这是一种常用技巧,若能善用,能有效引导观众关注特定数据点。

有效使用颜色的另一个例子

有时,我们会使用相关性热力图。例如,我有“Dirty Devil”数据,并希望计算所有数值列之间的相关性。如果直接看数据表格,虽然能沿对角线看到数值1,但很难一眼看出哪些是高度正相关,哪些是负相关。人类并不擅长直接阅读数据表格,因此我们可以借助颜色来辅助理解。

我常看到人们这样做:直接应用一个默认的配色方案。这里我们应用了默认的背景渐变色,现在可以清楚地看到对角线上的蓝色非常突出。但是,如何找到最强的负相关性呢?这有点困难,我们可能需要寻找最白的区域,但实际上我们应该使用不同的配色方案。

有时,人们会使用像“viridis”这样的配色方案。“viridis”是一种类似彩虹的渐变色系,会从黄色渐变到紫色,中间经过绿色和蓝色。在这种情况下,我们可以寻找最黄和最紫的区域。但由于图中还有其他亮色,它并不能完美地突出我们想关注的重点。

正确的配色方案:发散色系

实际上,对于相关性热力图,我们应该使用发散色系,例如下面这个红-蓝配色方案。它从红色渐变到白色,再渐变到蓝色。现在,我们可以寻找最蓝和最红的区域。但这里也存在一个我常见到的错误做法。

特别是在相关性热力图中,我们需要固定颜色映射的边界值。目前,正值被固定在1,对应蓝色。但对于负值,我们不希望最负的值显示为红色,我们希望-1对应红色,因为0附近的数值应该显示为白色。

为了实现这一点,至少在pandas中,我们需要设置vminvmax参数。根据你使用的库,设置方式可能不同,但这是一个正确的做法。

以下是适用于此相关性可视化的正确配色方案示例代码:

# 设置颜色映射的边界,使-1对应红色,0对应白色,1对应蓝色
heatmap = df.corr().style.background_gradient(cmap='RdBu', vmin=-1, vmax=1)

我们已将vmin设为-1,意味着如果某个值是-1,它将显示为红色。在本例中,我们没有恰好为-1的值,最小的值大约在-0.15左右。我们不希望这些值显示为深红色,因为我们希望0附近的值是白色的。同时,我们将vmax设为1。虽然在此类相关性图中对角线本来就是1,但为了明确起见,我们还是设置了它。

这个可视化效果比之前看到的要好得多,因为它清晰地显示了我们有一些强正相关性,同时也有一些非常弱的浅色相关性。其他图表都没有如此清晰地展示这一点。

选择合适的配色方案

如果你使用Matplotlib,可以参考这里链接的速查表。我们有各种不同的配色方案,你需要根据情况选择合适的。

例如,我们刚刚讨论了相关性图,因此你应该使用发散色系中的一种。

如果你查看的是类别数据,并且希望不同类别之间区分明显,你可能需要查看定性色系

还有其他配色方案,比如“twilight”,它可能具有特殊的循环属性。如果你的数据是重复的(例如年份信息),你可能希望使用循环色系来使颜色周期性地回到起始值。

总结

本节课我们一起学习了数据可视化中颜色方案的选择与优化。核心要点包括:避免创建混乱的“意大利面条图”,学会通过高亮单一线条来突出重点;理解在相关性热力图中使用发散色系(如RdBu)并正确设置vminvmax参数的重要性;以及根据数据类型(连续、发散、定性、循环)选择匹配的Matplotlib配色方案。正确的颜色使用能极大提升图表的清晰度和信息传达效率。

113:探索基础图表类型 📊

在本节课中,我们将学习如何使用Pandas库加载数据,并探索几种常见的基础图表类型。我们将通过一个河流流量数据集来演示如何创建折线图、直方图、散点图和条形图,并学习如何通过调整图表来更好地理解数据。


加载数据集

首先,我们需要加载一个名为“Di Devil”的数据集。这是一个关于犹他州南部一条河流流量的数据集。数据集包含多个列,例如:

  • CFS:立方英尺每秒,表示流量。
  • gauge height:水位高度。
  • date:日期。
  • temperature:温度信息。
  • 此外,还有一些分类性质的列,如流量的分箱和季度信息。

这个数据集包含了有趣的时序信息,既有数值型数据,也有分类数据。

# 示例:加载数据集(假设文件名为‘river_data.csv’)
import pandas as pd
df = pd.read_csv(‘river_data.csv’)

创建折线图

上一节我们加载了数据集,本节中我们来看看如何创建折线图来观察数据随时间的变化趋势。

在Pandas中创建折线图非常简单。我们可以指定X轴为日期列,Y轴为流量(CFS)列。

df.plot(x=‘date’, y=‘CFS’)

这个图表虽然容易制作,但可能不够清晰。可以看到X轴标签非常拥挤,并且有一些异常值拉伸了Y轴,使我们难以看清主要数据的变化。

为了改善这一点,我们可以尝试将每年的数据单独绘制成一条线,以便比较不同年份间的模式。这需要对数据进行透视操作。

# 假设我们已创建一个以年份为列的透视表 ‘df_pivot’
df_pivot.plot()

调整后的图表看起来更有趣一些,但异常值问题依然存在,并且多条彩色线条交织在一起,显得有些混乱。

我们可以使用Matplotlib库来设置Y轴的范围,从而放大我们感兴趣的数据区域。

import matplotlib.pyplot as plt
df_pivot.plot()
plt.ylim([0, 1000]) # 设置Y轴显示范围

放大后,故事开始变得清晰,但颜色仍然繁多。通常,更好的做法是淡化所有线条的颜色,只高亮显示特定的一年来讲述故事。你可以选择关注最大值、最小值或中心趋势的年份。

此外,对于时间序列数据,常见的平滑技术是计算滚动平均值。这可以让趋势线更平滑。

# 计算7日滚动平均后绘图
df_pivot.rolling(window=7).mean().plot()

创建直方图

接下来,我们看看如何用直方图来理解单个数值变量的分布。

直方图在Pandas中非常容易创建。我们只需选择要绘制的列,并调用.hist()方法。我们还可以指定分箱的数量。

以下是创建水位高度直方图的步骤:

df[‘gauge height’].hist(bins=30)

这个直方图显示了水位高度的中心趋势。最常见的值大约在3左右。


创建散点图与理解相关性

当我们想比较两个数值变量时,散点图是一个很好的选择。在绘制之前,我们可以先计算它们之间的相关性进行总结。

我们将使用斯皮尔曼等级相关系数来总结水位高度和流量之间的关系。这个系数介于-1到1之间。1表示完全正相关(一个变量的排名上升,另一个的排名也上升),0表示无相关性,-1表示完全负相关。

correlation = df[‘gauge height’].corr(df[‘CFS’], method=‘spearman’)
print(f“斯皮尔曼相关系数为:{correlation:.2f}”)

计算结果显示存在轻微的正相关。为了直观地理解这种关系,我们可以绘制散点图。

df.plot.scatter(x=‘gauge height’, y=‘CFS’)

从散点图中,我们可以看到数据点有轻微向上的趋势,但在水位高度为3附近出现了一些异常行为。

如果存在这样的异常值,我们需要思考:是要聚焦于这些异常点,还是关注其他部分?我们可以再次使用Matplotlib来放大图表的Y轴范围,以便更仔细地观察主要数据区域。同时,按年份给数据点上色可能会揭示更多信息。

plt.scatter(df[‘gauge height’], df[‘CFS’], c=df[‘year’], alpha=0.5)
plt.ylim([0, 5000]) # 放大Y轴
plt.colorbar(label=‘Year’)

当进行这样的探索时,我注意到在水位高度3处有一条垂直的线,这看起来不太自然。这个发现可能会促使我深入检查这一年的原始数据,看看是否是测量仪器出现了问题。


创建条形图

最后,我们来看看如何用条形图来理解和总结分类数据。

条形图非常适合展示不同类别下的汇总统计量(如平均值、中位数)。在本例中,我们将按月份汇总流量数据,并查看每个月流量的中位数。

以下是创建按月份流量中位数条形图的步骤:

# 按月份分组并计算CFS的中位数
monthly_median = df.groupby(‘month’)[‘CFS’].median()
monthly_median.plot(kind=‘bar’)

通过这个条形图,我们可以快速理解数据。可以看到,二月份的流量中位数最高,而七月份的流量中位数倾向于最低。这个图表很好地说明了如何通过条形图来总结分类数据(本例中将月份视为类别)。


总结

本节课中,我们一起学习了几种常见的数据类型及其对应的基础图表。

  • 我们使用折线图来观察时间序列趋势,并学习了通过数据透视设置坐标轴范围计算滚动平均来优化图表。
  • 我们使用直方图来了解单个数值变量的分布情况。
  • 我们通过计算斯皮尔曼相关系数和绘制散点图来探索两个数值变量之间的关系,并在过程中发现了可能需要进一步调查的异常数据。
  • 最后,我们使用条形图来有效地总结和比较分类数据。

当你拿到数据时,首先要理解数据代表什么,然后选择一个能讲述你想要的故事的图表类型。探索性数据分析是发现数据中隐藏模式和问题的关键第一步。

114:数据清洗技术 🧹

在本节中,我们将学习如何使用Python清洗数据。我们将通过一个具体示例,演示如何从GitHub加载两个数据集(河流流量数据和温度数据),对它们进行清理、转换和合并,最终生成一个可用于分析的整洁数据集。

上一节我们介绍了数据加载的基础知识,本节中我们来看看如何将这些原始数据转化为干净、可用的格式。

概述

我们将处理两个来自美国国家海洋和大气管理局(NOAA)的数据集:关于“Dirty Devil River”的河流流量数据,以及附近“Hanksville”的温度数据。目标是合并这两个数据集,并在此过程中进行一系列数据清洗操作,包括处理日期时间、重命名列、分组聚合、处理缺失值以及创建新的分类变量。

数据加载

首先,我们需要加载原始数据。以下是加载河流数据集的代码示例。请注意,我们使用了一个lambda函数来跳过文件开头的几行无关信息。

import pandas as pd

# 加载河流数据,跳过文件开头的几行
river_data = pd.read_csv('river_data.csv', skiprows=lambda x: x in [0, 1, 2])

加载完成后,我们得到了原始的河流数据集。接下来,我们以类似的方式加载温度数据,该数据同样可以从GitHub获取。

# 加载温度数据
temperature_data = pd.read_csv('temperature_data.csv')

现在,我们手头有了两个独立的数据集。下一步是将它们清理并合并在一起。

清洗河流数据

我们定义一个名为 tweak_river 的函数来处理河流数据。清洗过程是一个链式操作。

首先,我们需要创建一个正确的 datetime 列。原始数据中的日期时间信息需要被转换为Pandas的日期时间格式,并指定时区为美国丹佛时间(‘America/Denver’)。

def tweak_river(df):
    # 创建日期时间列并转换时区
    df['datetime'] = (pd.to_datetime(df['datetime'])
                      .dt.tz_localize('UTC')
                      .dt.tz_convert('America/Denver'))
    return df

上述代码中的时区转换过程可以更详细地解释。其核心步骤是:

  1. 将字符串转换为无时区信息的 datetime 对象。
  2. 将其本地化为UTC时间。
  3. 再转换为目标时区(‘America/Denver’)。

创建好日期时间列后,我们重命名两个数值列,使它们的名称更清晰易懂。

def tweak_river(df):
    # ...(之前的日期时间转换代码)
    # 重命名列
    df = df.rename(columns={'flow_cfs': 'CFS', 'gauge_height_ft': 'gauge_height'})
    return df

至此,河流数据的基本清洗就完成了。回到主流程,我们调用 tweak_river 函数处理原始数据。

cleaned_river = tweak_river(river_data)

聚合与合并温度数据

现在,让我们看看温度数据的清洗过程。对于温度数据,我们同样需要处理日期,并选择相关的列。

def tweak_temp(df):
    # 创建日期列并转换时区
    df['date'] = pd.to_datetime(df['DATE']).dt.tz_localize('America/Denver')
    # 选择需要的列
    df = df[['date', 'PRCP', 'TMIN', 'TMAX', 'TOBS']]
    # 重命名列以使其含义明确
    df = df.rename(columns={'PRCP': 'precipitation',
                            'TMIN': 'temp_min',
                            'TMAX': 'temp_max',
                            'TOBS': 'temp_observed'})
    return df

温度数据清洗完成后,我们将其与之前处理过的河流数据合并。合并的依据是日期:河流数据按天聚合后的日期索引,与温度数据的日期列。

在合并之前,我们需要对河流数据进行按日聚合,计算每日流量的中位数等统计值。

# 将河流数据按天聚合,计算数值列的中位数
daily_river = cleaned_river.groupby(pd.Grouper(key='datetime', freq='D')).median()

现在,合并两个数据集:

# 合并数据
merged_data = pd.merge(daily_river, cleaned_temp,
                       left_index=True, # 使用daily_river的日期索引
                       right_on='date') # 使用cleaned_temp的‘date’列

创建衍生特征

数据合并后,我们可以创建一些新的特征列,以便进行更深入的分析。

以下是需要创建的新列:

  • 年积日:一年中的第几天。
  • 月份:提取日期中的月份。
  • 年份:提取日期中的年份。
  • 处理后的水位高度:使用插值法填充缺失的水位值,并对前端的缺失值进行后向填充。
  • 流量分级:根据立方英尺每秒(CFS)的值,将其分为“低流量”(前10%)、“中流量”(中间80%)和“高流量”(后10%)三个等级。
  • 季度:提取日期所属的季度。
# 创建衍生特征
merged_data['day_of_year'] = merged_data['date'].dt.dayofyear
merged_data['month'] = merged_data['date'].dt.month
merged_data['year'] = merged_data['date'].dt.year

# 插值并填充水位高度
merged_data['gauge_height_filled'] = merged_data['gauge_height'].interpolate().bfill()

# 创建流量分级
bins = merged_data['CFS'].quantile([0, 0.1, 0.9, 1.0]).tolist()
labels = ['低流量', '中流量', '高流量']
merged_data['CFS_bin'] = pd.cut(merged_data['CFS'], bins=bins, labels=labels, include_lowest=True)

# 创建季度
merged_data['quarter'] = merged_data['date'].dt.quarter

保存结果

所有清洗和转换步骤完成后,我们将最终的数据集保存为CSV文件,供后续分析使用。

merged_data.to_csv('cleaned_merged_data.csv', index=False)

最终的数据集包含以下列:站点编号、日立方英尺每秒流量、水位高度、日期、降水量、日最低温、日最高温、观测温度、年积日、月份、年份、流量分级和季度。这个整洁的数据集现在已准备好用于可视化、建模或其他分析任务。

总结

本节课中我们一起学习了使用Pandas进行数据清洗的完整流程。我们通过一个实例,演示了如何从加载原始数据开始,逐步进行时区转换、列重命名、数据聚合、表合并、缺失值处理以及创建衍生特征。关键点在于将复杂的清洗任务分解为一个个小的、可管理的函数或步骤,并通过链式调用保持代码的清晰。掌握这些技术,你就能将杂乱的真实世界数据转化为结构清晰、可用于分析的高质量数据集。

115:使用Pandas创建折线图 📈

在本节课中,我们将学习如何使用Pandas和Matplotlib库,从原始数据开始,逐步创建并完善一个能够讲述故事的折线图。我们将复现一个关于各国人均医疗支出与预期寿命关系的图表。

概述与数据准备

首先,我们需要加载必要的库和数据。我们将使用Matplotlib进行绘图,NumPy和Pandas进行数据处理。

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

数据来源于两个数据集:医疗支出数据和预期寿命数据。以下是加载数据的代码:

# 数据URL(示例)
spending_url = '...'
life_expectancy_url = '...'

spending_df = pd.read_csv(spending_url)
life_df = pd.read_csv(life_expectancy_url)

加载数据后,我们需要将这两个数据集合并,以便后续分析。

数据清洗与合并

上一节我们加载了数据,本节中我们来看看如何清洗和合并数据。我们定义一个函数 tweak_data 来处理数据。

以下是该函数执行的关键步骤:

  1. 对支出数据框进行查询,筛选出度量标准为“人均美元”且主题为“总计”的行。
  2. 按“时间”和“地点”分组,并提取每个组的第一条记录的值。
  3. 将该值列重命名为“spending_USD”并转换为数据框。
  4. 对预期寿命数据按“时间”和“地点”分组,计算平均值,并将列名改为“life_expectancy”。
  5. 将处理后的两个数据框合并,并重置索引。
def tweak_data(spending_df, life_df):
    # 处理支出数据
    spending_processed = (spending_df
                          .query('measure == "USD_cap" & subject == "TOT"')
                          .groupby(['time', 'location'])
                          .first()['value']
                          .rename('spending_USD')
                          .to_frame())
    
    # 处理预期寿命数据
    life_processed = (life_df
                      .groupby(['time', 'location'])['value']
                      .mean()
                      .rename('life_expectancy')
                      .to_frame())
    
    # 合并数据并重置索引
    merged_df = spending_processed.merge(life_processed, 
                                         left_index=True, 
                                         right_index=True)
    return merged_df.reset_index()

df = tweak_data(spending_df, life_df)

处理完成后,我们得到一个包含time(时间)、location(国家/地区)、spending_USD(人均医疗支出)和life_expectancy(预期寿命)列的数据框。

创建基础折线图

数据准备就绪后,我们现在可以开始创建图表。首先,我们尝试用最少的代码绘制一个基础版本。

核心思路是:按国家分组,为每个国家绘制一条“支出-寿命”的折线。在Pandas中,这可以通过groupbyapply方法结合绘图函数实现。

# 基础绘图函数
def basic_plot(group):
    group.plot(x='spending_USD', y='life_expectancy', ax=plt.gca())

# 应用分组绘图
df.groupby('location').apply(basic_plot)
plt.show()

生成的图表包含了所有国家的数据线,虽然功能完整,但线条混杂,重点不突出,可读性较差。Pandas的优势在于可以轻松处理这种非单调(线条可回折)的数据序列。

突出显示关键数据

基础图表信息过载,本节中我们来看看如何优化它以讲述一个更清晰的故事。我们希望像原图一样,将美国的线标为红色并高亮显示,其他国家的线则用灰色淡化。

我们需要修改绘图函数,根据国家名称动态设置线条颜色,并在线尾添加国家标签。

def highlighted_plot(group):
    name = group.name # 获取组名(即国家名)
    # 设定颜色:美国为红色,其他国家为灰色
    color = 'red' if name == 'United States' else '#d3d3d3'
    
    ax = plt.gca()
    # 按时间排序后绘图
    group.sort_values('time').plot(x='spending_USD', 
                                   y='life_expectancy', 
                                   color=color, 
                                   ax=ax)
    # 在线条末端添加国家标签
    ax.text(x=group['spending_USD'].iloc[-1],
            y=group['life_expectancy'].iloc[-1],
            s=name,
            color=color)

应用这个函数后,图表的故事性立刻增强:美国的高支出与相对较低的预期寿命形成了鲜明对比。

完善图表样式

图表的故事线已经清晰,但样式仍可优化。本节我们将添加网格、调整坐标轴、设置标签和标题,让图表更加专业和易读。

以下是完善图表样式的关键步骤代码:

# 1. 数据过滤与分组绘图
filtered_df = df[(df['life_expectancy'].max() > 80) | (df['location'] == 'United States')]
filtered_df.groupby('location').apply(highlighted_plot)

ax = plt.gca()

# 2. 设置坐标轴范围与刻度
ax.set_ylim(70, 84)
ax.set_xlim(0, 11000)
ax.xaxis.set_major_locator(plt.MultipleLocator(2000))
ax.xaxis.set_minor_locator(plt.MultipleLocator(500))

# 3. 设置网格样式
ax.grid(which='major', linewidth=1, color='gray', zorder=0)
ax.grid(which='minor', linewidth=0.5, color='lightgray', zorder=0)

# 4. 设置边框颜色
for spine in ax.spines.values():
    spine.set_color('gray')

# 5. 添加标签和标题
ax.set_ylabel('Life Expectancy (years)')
ax.set_xlabel('Health Expenditure per Capita (USD)')
ax.set_title('Life Expectancy vs. Health Spending by Country (1970-2020)')

# 6. 添加脚注
ax.annotate('Source: Our World in Data', 
            xy=(0.5, -0.1), 
            xycoords='axes fraction', 
            ha='center', 
            fontsize=9, 
            color='gray')

plt.tight_layout()
plt.show()

通过以上步骤,我们得到了一个样式精美、信息完整的图表。它有效地突出了核心故事,并通过专业的视觉元素引导读者理解数据。

总结

本节课中我们一起学习了如何使用Pandas和Matplotlib创建并优化一个叙事性强的折线图。我们从数据加载和清洗开始,经历了创建基础图表、高亮关键数据、到最终完善图表样式的全过程。关键收获在于,通过数据过滤条件格式化(如颜色设置)和细致的样式调整,我们可以将原始数据转化为一个能够清晰、有力传达信息的可视化作品。这种将数据分析与视觉叙事相结合的能力,是数据工程和可视化中的核心技能。

116:使用Pandas创建条形图 📊

在本节课中,我们将学习如何使用Pandas和Matplotlib创建条形图。我们将从一个简单的条形图开始,然后逐步进行大量自定义,最终目标是模仿《经济学人》杂志风格的一个复杂条形图。条形图是汇总分类数据计数的绝佳工具。

概述

本节我们将学习创建条形图的基础知识,并深入探索如何自定义其外观,包括调整颜色、字体、网格、边框(spines)以及添加文本标注,以实现专业出版物的视觉效果。


创建基础条形图

首先,我们从一个简单的条形图开始。以下是创建基础条形图的步骤。

我们从一个手动创建的数据集开始。调用plot方法并指定X轴和Y轴的数据,即可生成基础条形图。

# 假设 df 是我们的DataFrame,包含 'Category' 和 'Count' 两列
df.plot(kind='bar', x='Category', y='Count')

对于个人使用,这样的图表可能已经足够。但为了获得更好的可读性,我们通常更喜欢水平条形图,这样类别标签更容易阅读。

df.plot(kind='barh', x='Category', y='Count')

自定义条形图以模仿专业风格

上一节我们介绍了基础条形图。本节中,我们来看看如何通过一系列自定义步骤,使图表更接近《经济学人》杂志的风格。这需要更多的代码,但能显著提升图表的专业外观。

以下是实现高度自定义条形图的关键步骤:

  1. 设置字体与颜色:在绘图开始时,定义全局字体和颜色方案。
  2. 创建图形与坐标轴:使用plt.subplots()显式创建图形(figure)和坐标轴(axes)对象,以便进行精细控制。
  3. 准备数据:对数据框进行排序,确保条形顺序符合预期。
  4. 绘制水平条形图:使用ax.barh()方法绘制条形。
  5. 自定义坐标轴刻度:设置X轴的刻度位置和标签,例如从0到14,步长为2。同时,将刻度标签置于顶部,并隐藏底部标签和Y轴标签。
  6. 添加网格线:仅在X轴方向添加主要网格线,并设置其线宽和颜色。
  7. 处理边框(Spines):隐藏图表四周的边框线(spines),然后将左侧的边框线加粗并置于条形图上方(通过设置zorder)。
  8. 添加装饰元素:使用patches(图形块)系统在图表顶部绘制红色方框和线条。
  9. 添加文本:使用text方法在图表中添加主标题、副标题以及数据来源标注。

通过以上步骤,我们虽然使用了比默认绘图多得多的代码行,但成功复制了《经济学人》图表的外观和感觉。Matplotlib提供了几乎无限的自定义能力,允许你调整图表的每一个细节。


总结

本节课中我们一起学习了如何使用Pandas和Matplotlib创建和自定义条形图。我们从最简单的条形图开始,逐步添加了字体设置、颜色调整、网格线、边框控制以及文本标注等高级功能。关键点在于,Matplotlib提供了底层控制能力,只要你愿意投入代码,就能实现任何你想要的视觉效果。记住,好的可视化不仅是展示数据,更是清晰、美观地传达信息。

117:使用Pandas创建散点图 📊

在本节课中,我们将学习如何使用Pandas和Matplotlib创建散点图。散点图是一种强大的数据可视化工具,用于探索两个数值变量之间的关系。我们将从一个基础图表开始,逐步美化它,使其达到专业出版物的水准。

什么是散点图?

上一节我们介绍了不同类型的数据可视化图表。本节中,我们来看看散点图的具体应用。

散点图允许你观察两个数值之间的关系。每个数据点在图中的位置由其两个变量的值(X轴和Y轴)共同决定,这有助于揭示变量之间是否存在相关性、趋势或异常值。

准备数据

在绘制图表之前,我们需要准备好要使用的数据。以下是本节课将用到的数据集,它包含了不同国家每百人枪支拥有量和每亿人大规模枪击案数量的信息。

import pandas as pd

# 假设数据已复制到剪贴板,可以使用以下方式读取
# df = pd.read_clipboard()

# 为演示,这里手动创建一个示例DataFrame
data = {
    'Country': ['United States', 'Yemen', 'Switzerland', 'Finland', 'Canada', 'Germany', 'France', 'Australia'],
    'Guns_per_100': [120.5, 54.8, 45.7, 32.4, 30.8, 19.6, 31.2, 14.5],
    'Mass_Shootings_per_100M': [4.5, 0.2, 0.1, 0.3, 0.5, 0.2, 0.1, 0.1]
}
df = pd.DataFrame(data)
print(df.head())

运行上述代码将加载数据并显示前几行,让我们了解数据结构。

创建基础散点图

现在我们已经有了数据,接下来创建第一个散点图。基础散点图的绘制非常简单。

以下是使用Pandas的.plot.scatter()方法创建散点图的核心代码:

# 创建基础散点图
ax = df.plot.scatter(x='Guns_per_100',
                     y='Mass_Shootings_per_100M',
                     figsize=(10, 6))
ax.set_title('基础散点图:枪支拥有量与大规模枪击案的关系')
ax.set_xlabel('每百人枪支拥有量')
ax.set_ylabel('每亿人大规模枪击案数量')

这段代码会生成一个基础图表,其X轴代表“每百人枪支拥有量”,Y轴代表“每亿人大规模枪击案数量”。这个图表已经能讲述基本的数据故事,例如,美国在图表中的位置表明其在这两项指标上都显著高于其他国家。

美化散点图

基础图表功能完备,但外观可以更加精美。接下来,我们将使用Matplotlib对图表进行深度定制,使其风格更接近《纽约时报》等专业出版物。

我们首先导入Matplotlib,并进行一系列样式设置。

import matplotlib.pyplot as plt

# 设置字体和颜色
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['axes.edgecolor'] = '#d3d3d3'  # 浅灰色边框

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(12, 8))

# 绘制散点
scatter = ax.scatter(df['Guns_per_100'],
                     df['Mass_Shootings_per_100M'],
                     color='steelblue',
                     s=100,  # 点的大小
                     alpha=0.7)  # 点的透明度

# 设置标题和坐标轴标签
ax.set_title('枪支拥有量与大规模枪击案的国际比较', fontsize=16, pad=20)
ax.set_xlabel('每百人枪支拥有量', fontsize=12)
ax.set_ylabel('每亿人大规模枪击案数量', fontsize=12)

添加数据标签和注释

为了让图表信息更清晰,我们需要为特定的数据点(国家)添加标签。以下是添加注释和标签的步骤。

首先,我们定义需要特别标注的国家列表,然后循环为它们添加文本标签。

# 定义需要标注的国家
countries_to_label = ['United States', 'Yemen', 'Switzerland', 'Finland']

# 循环为特定国家添加文本标签
for country in countries_to_label:
    # 查询该国家的数据行
    row = df[df['Country'] == country].iloc[0]
    x = row['Guns_per_100']
    y = row['Mass_Shootings_per_100M']

    # 添加文本标签,根据国家位置调整标签方位
    if country in ['United States', 'Yemen']:
        # 将美国和也门的标签放在点左侧
        ax.annotate(country,
                    xy=(x, y),
                    xytext=(-80, 0),  # 文本相对于点的偏移量
                    textcoords='offset points',
                    ha='right',
                    va='center',
                    fontsize=10,
                    arrowprops=dict(arrowstyle='->',
                                    color='gray',
                                    lw=1,
                                    connectionstyle="arc3,rad=0.2"))
    else:
        # 将其他国家的标签放在点右侧
        ax.annotate(country,
                    xy=(x, y),
                    xytext=(20, 0),  # 文本相对于点的偏移量
                    textcoords='offset points',
                    ha='left',
                    va='center',
                    fontsize=10,
                    arrowprops=dict(arrowstyle='->',
                                    color='gray',
                                    lw=1,
                                    connectionstyle="arc3,rad=0.2"))

调整坐标轴与网格

最后,我们对坐标轴的刻度、样式以及网格线进行精细调整,以提升图表的可读性和美观度。

以下是调整坐标轴和添加网格的代码:

# 调整刻度位置和标签(示例:自定义X轴刻度)
ax.set_xticks([0, 25, 50, 75, 100, 125])
# 可以自定义刻度标签,这里使用默认数值标签

# 移除朝向图形内部的刻度(ticks)
ax.tick_params(axis='both', which='both', length=0)

# 设置坐标轴线(脊柱)颜色为浅灰色
for spine in ax.spines.values():
    spine.set_color('#d3d3d3')
    spine.set_linewidth(1)

# 添加网格线
ax.grid(True, which='major', axis='both',
        linestyle='--', linewidth=0.5, color='lightgray', alpha=0.7)

# 自动调整布局并显示图形
plt.tight_layout()
plt.show()

运行全部代码后,你将得到一个信息丰富、外观专业的散点图,清晰地展示了不同国家在两个指标上的分布情况。

总结

本节课中我们一起学习了如何使用Pandas和Matplotlib创建并美化散点图。我们从加载数据、绘制基础图表开始,逐步深入到使用Matplotlib进行定制化设置,包括调整样式、添加数据标签与注释、以及优化坐标轴和网格。掌握这些技能后,你将能够创建出可用于专业报告和出版物的高质量数据可视化图表。

118:使用Pandas创建复杂图表 📊

在本节中,我们将学习如何使用Pandas创建一些更为复杂的图表。这将展示我们不仅能用Pandas制作非常简单的图表,还能深入定制它们以满足特定需求。通常,当我们需要为演示讲述一个清晰的数据故事时,会进行定制;而在自行探索数据时,则可能跳过这些步骤,因为定制过程比创建简单图表更为复杂。

现在,让我们看看如何在Pandas中实现这一点。


上一节我们介绍了Pandas的基础绘图功能,本节中我们来看看如何通过定制来创建更复杂的图表。

以下是创建复杂图表的基本步骤:

  1. 导入必要的库:首先,确保导入了Pandas和Matplotlib。

    import pandas as pd
    import matplotlib.pyplot as plt
    
  2. 加载数据:将你的数据加载到Pandas DataFrame中。

    df = pd.read_csv('your_data.csv')
    
  3. 创建基础图表:使用DataFrame的plot方法生成一个基础图表。

    df.plot(kind='line', x='date', y='value')
    
  4. 定制图表元素:通过Matplotlib的API定制标题、坐标轴标签、图例等。

    plt.title('自定义图表标题')
    plt.xlabel('X轴标签')
    plt.ylabel('Y轴标签')
    plt.legend(['图例项'])
    
  5. 调整样式与布局:可以进一步调整颜色、线型、网格等,并优化图表布局。

    plt.grid(True)
    plt.tight_layout()
    
  6. 保存或显示图表:最后,将图表保存为图像文件或直接显示出来。

    plt.savefig('complex_plot.png')
    plt.show()
    

通过遵循以上步骤,你可以将简单的Pandas图表转化为信息丰富、视觉吸引力强的复杂图表。关键在于结合Pandas的便捷性与Matplotlib的强大定制能力。


本节课中我们一起学习了如何使用Pandas创建并定制复杂图表。我们了解了从基础绘图到深度定制的完整流程,包括导入库、加载数据、生成图表以及通过Matplotlib进行各种视觉元素的调整。掌握这些技能后,你将能够为不同场景(无论是数据探索还是正式演示)制作出更贴合需求的图表。

119:使用Pandas创建热力图 🔥

在本节课程中,我们将学习如何使用Pandas和Matplotlib创建热力图。热力图是一种通过颜色变化来展示数据矩阵中数值大小的可视化方法,特别适用于展示多个变量之间的相关性或比较不同类别的数据。

上一节我们介绍了数据的基本处理,本节中我们来看看如何将处理好的数据以热力图的形式直观呈现。

数据准备与处理

首先,我们需要加载必要的库并读取数据。数据来源于Siena College Research Institute关于美国总统的排名数据,包含20个维度的评分。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# 读取数据并应用预处理函数
df = pd.read_csv('president_rankings.csv')
df = tweak_siena_pres(df)

以下是tweak_siena_pres预处理函数所执行的关键步骤:

  • 重命名列:将SeQ.列重命名为SeQ,并使用字典推导式将所有缩写列名替换为完整的名称。
  • 数据类型转换:将party列转换为分类数据类型,并将所有整数列从int64转换为更节省内存的uint8类型。
  • 创建新列:计算所有数值列的平均排名,并生成一个表示排名分位数的quartile列。

处理后的数据框结构如下,我们主要关注从backgroundoverall的评分列。

# 设置索引并选择需要绘图的数值列
plot_df = df.set_index('president').iloc[:, :-2]

在Pandas中生成简易热力图

Pandas的DataFrame有一个便捷的style.background_gradient方法,可以直接在Jupyter Notebook等环境中生成HTML格式的热力图。

# 在Pandas中生成带颜色背景的表格(热力图效果)
styled_df = plot_df.style.background_gradient(cmap='coolwarm')
styled_df

这种方法快速简便,但生成的是静态HTML表格,无法进行深度定制或轻松保存为高质量的图像文件。

使用Matplotlib创建定制化热力图

为了获得可定制且可保存的热力图,我们需要借助Matplotlib。Matplotlib本身没有直接的“heatmap”函数,但我们可以组合其基础功能来实现。

以下是实现热力图的核心代码框架,它定义了绘图、配色和注释的步骤:

def heatmap(data, row_labels, col_labels, ax=None,
            cbar_kw=None, cbarlabel="", **kwargs):
    """
    根据数据矩阵创建热力图。
    """
    if ax is None:
        ax = plt.gca()
    if cbar_kw is None:
        cbar_kw = {}

    # 绘制热力图
    im = ax.imshow(data, **kwargs)

    # 创建颜色条
    cbar = ax.figure.colorbar(im, ax=ax, **cbar_kw)
    cbar.ax.set_ylabel(cbarlabel, rotation=-90, va="bottom")

    # 设置坐标轴刻度
    ax.set_xticks(np.arange(data.shape[1]))
    ax.set_yticks(np.arange(data.shape[0]))
    ax.set_xticklabels(col_labels)
    ax.set_yticklabels(row_labels)

    # 旋转x轴标签并设置对齐方式
    plt.setp(ax.get_xticklabels(), rotation=45, ha="right",
             rotation_mode="anchor")

    return im, cbar

def annotate_heatmap(im, data=None, valfmt="{x:.2f}",
                     textcolors=("black", "white"), threshold=None):
    """
    在热力图的每个单元格中添加文本注释。
    """
    if not isinstance(data, (list, np.ndarray)):
        data = im.get_array()

    # 设置文本颜色的阈值
    if threshold is not None:
        threshold = im.norm(threshold)
    else:
        threshold = im.norm(data.max())/2.

    # 遍历数据矩阵,添加文本
    kw = dict(horizontalalignment="center",
              verticalalignment="center")
    for i in range(data.shape[0]):
        for j in range(data.shape[1]):
            kw.update(color=textcolors[int(im.norm(data[i, j]) > threshold)])
            im.axes.text(j, i, valfmt.format(data[i, j]), **kw)

以下是使用上述函数绘制最终热力图的步骤:

  1. 设置图形与颜色:创建图形,设置背景色,并定义数据矩阵和标签。
  2. 调用热力图函数:使用自定义的heatmap函数绘制基础热力图。
  3. 添加注释:调用annotate_heatmap函数在每个单元格中显示具体数值。
  4. 添加标题与装饰:为图表和颜色条添加标题,并调整颜色条的样式(如边框颜色、刻度颜色)。
# 准备数据与标签
skills = [col.replace('_', ' ') for col in plot_df.columns]
presidents = plot_df.index

fig, ax = plt.subplots(figsize=(12, 8))
fig.patch.set_facecolor('black')

# 绘制热力图
im, cbar = heatmap(plot_df.values, presidents, skills, ax=ax,
                   cmap="coolwarm", cbarlabel="Rank")
# 为颜色条添加白色边框和标题
cbar.outline.set_edgecolor('white')
cbar.ax.tick_params(colors='white')
cbar.ax.set_ylabel('Rank', color='white')

# 添加数值注释
annotate_heatmap(im, valfmt="{x:.0f}")

# 添加主标题和副标题
ax.set_title("Presidential Leadership Survey", color='white', pad=20, size=16)
ax.text(0.5, 1.05, "Siena College Research Institute (2022)",
        transform=ax.transAxes, ha='center', color='lightgray')

plt.tight_layout()
plt.show()

总结

本节课中我们一起学习了创建热力图的两种方法。我们首先使用Pandas的style.background_gradient快速生成一个交互式的热力图预览。接着,我们深入使用Matplotlib,通过组合imshow、颜色条和文本注释等功能,从头构建了一个高度定制化的热力图,并实现了添加数值标签、自定义颜色映射和样式美化。

需要指出的是,Pandas和Matplotlib都没有提供开箱即用的单一热力图函数。对于更复杂或更标准的热力图需求,Seaborn库sns.heatmap函数通常是更简单、更强大的选择,这将在后续课程中介绍。本节的手动实现方法有助于理解热力图的构成原理,并提供了最大的灵活性。

120:使用Pandas创建斜率图 📈

在本节中,我们将学习如何创建一种名为“斜率图”的图表。斜率图并非我之前介绍过的标准图表类型,但它是折线图的一种变体,能够有效地讲述数据背后的故事。

概述

我们将通过一个具体案例来学习斜率图的创建。该案例比较了在五个不同城市中,使用Uber出行与拥有私家车的成本。我们的目标是复现一个能清晰传达“在五个城市中的四个,使用Uber比拥有私家车更便宜”这一结论的图表。

准备数据与基础绘图

首先,我们需要加载必要的库并创建示例数据。

import pandas as pd
import matplotlib.pyplot as plt

# 手动创建数据
data = {
    'city': ['New York', 'Los Angeles', 'Chicago', 'Dallas', 'Washington DC'],
    'Uber': [20, 18, 16, 12, 19],
    'personal car': [25, 22, 20, 10, 23]
}
df = pd.DataFrame(data)

为了使用Pandas绘制斜率图,我们需要对数据框进行转置,将城市名作为列,将出行方式(Uber和个人汽车)作为索引。

# 将‘city’列设为索引并转置数据框
df_slope = df.set_index('city').T
print(df_slope)

执行上述代码后,数据框的结构将发生变化,此时每一列代表一个城市,每一行代表一种出行方式。直接对这个转置后的数据框调用.plot()方法,Pandas会为每一列(即每个城市)绘制一条连接两种出行方式成本值的线段。

# 基础斜率图
df_slope.plot()
plt.show()

然而,这种方法绘制的图表可能不够直观。更常见的做法是使用柱状图进行对比。

上一节我们介绍了创建斜率图的数据准备步骤,本节中我们来看看如何通过柱状图进行初步的可视化。

# 使用原始数据框绘制分组柱状图
df.set_index('city').plot(kind='bar')
plt.show()

柱状图能够清晰地展示每个城市两种出行方式的成本对比。但是,它可能无法像斜率图那样突出地强调“在大多数城市,Uber成本线低于个人汽车成本线”这一整体趋势,尤其是在数据点较多时。

构建增强型斜率图

为了让故事更突出,我们将手动构建一个增强版的斜率图。这个版本会使用颜色、标签和注释来引导观众的视线。

以下是构建该图的核心步骤:

  1. 创建图形与坐标轴:初始化画布和坐标轴。
  2. 绘制线段:为每个城市绘制一条从“Uber”点到“个人汽车”点的线段。
  3. 定制坐标轴:隐藏不必要的边框和刻度,使图表更简洁。
  4. 添加标签与注释:在图表左右两侧添加城市名称和具体数值,并使用颜色高亮关键信息(例如,达拉斯的情况与其他城市相反)。
# 定义颜色和字体
uber_color = '#1f77b4'
car_color = '#ff7f0e'
highlight_color = 'red'  # 用于突出达拉斯
font_label = {'fontsize': 9, 'ha': 'center', 'va': 'center'}

fig, ax = plt.subplots(figsize=(8, 6))

# 设置X轴刻度位置和标签
x_positions = [0, 1]
x_labels = ['Uber', 'Personal Car']
ax.set_xticks(x_positions)
ax.set_xticklabels(x_labels)

# 隐藏Y轴刻度和 spines(边框)
ax.set_yticks([])
for spine in ['top', 'left', 'right']:
    ax.spines[spine].set_visible(False)
ax.spines['bottom'].set_position('zero')  # 将底部边框放在0位置

# 为每个城市绘制线段和标签
for idx, row in df.iterrows():
    city = row['city']
    uber_val = row['Uber']
    car_val = row['personal car']
    
    # 选择线段颜色:达拉斯用高亮色,其他用灰色
    line_color = highlight_color if city == 'Dallas' else 'lightgray'
    linewidth = 2.5 if city == 'Dallas' else 1
    
    # 绘制连接线
    ax.plot(x_positions, [uber_val, car_val], 
            marker='o', color=line_color, linewidth=linewidth)
    
    # 在左侧添加城市名和Uber成本
    ax.text(x_positions[0]-0.05, uber_val, f'{city}\n${uber_val}', 
            **font_label, ha='right')
    # 在右侧添加个人汽车成本
    ax.text(x_positions[1]+0.05, car_val, f'${car_val}', 
            **font_label, ha='left')

# 添加标题
ax.set_title('Cost Comparison: Uber vs Personal Car (per week)', pad=20)

plt.tight_layout()
plt.show()

通过上述代码,我们创建了一个信息丰富且重点突出的斜率图。观众的视线会被引导至达拉斯那条颜色不同的线段,从而立刻理解“除了达拉斯,其他城市使用Uber更便宜”的核心结论。

总结

本节课中我们一起学习了斜率图的创建与应用。我们首先了解了斜率图是一种用于比较两个时间点或状态间数据变化的有效工具。然后,我们通过Pandas的基础绘图功能和手动增强两种方式实现了斜率图。关键点在于,通过精心的设计(如数据转置、颜色高亮、添加直接标签和去除图表噪音),我们可以让同一个数据集讲述一个更清晰、更有力的故事。斜率图虽不常见,但在需要强调数据点之间变化和对比的场景下,它是一个非常强大的选择。

121:Pandas方法链式调用 🐼

在本节中,我们将学习Pandas中的方法链式调用。这是一种将多个操作按顺序连接起来的编程风格,可以使代码更清晰、更易于理解。

概述

方法链式调用允许我们在一行代码中连续执行多个Pandas操作。这种方式不仅使代码看起来像一份清晰的“食谱”,还能帮助我们更逻辑地思考每一步数据处理。

构建方法链

上一节我们介绍了Pandas的基本操作,本节中我们来看看如何通过链式调用将这些操作串联起来。

首先,我们从一个简单的数据读取开始。以下是读取数据并展示原始状态的代码:

df = pd.read_csv('data_url')
print(df)

逐步构建链式操作

以下是构建链式调用的关键步骤,我们将逐一讲解。

1. 重命名列

我们首先处理列名中的多余字符。例如,移除“seek”列名中的句点:

df = df.rename(columns={'seek.': 'seek'})

2. 使用字典推导式重命名

接下来,我们将使用字典推导式将缩写列名转换为更易读的名称:

rename_dict = {col: full_name for col, full_name in column_mapping.items()}
df = df.rename(columns=rename_dict)

3. 转换数据类型

为了优化内存和性能,我们将“party”列转换为分类类型:

df['party'] = df['party'].astype('category')

4. 优化数值类型

我们还将把int64类型的列转换为更节省空间的uint8类型:

int64_cols = df.select_dtypes(include=['int64']).columns
df[int64_cols] = df[int64_cols].astype('uint8')

5. 添加新列

最后,我们添加一些计算列,例如平均排名和四分位数:

df['average_rank'] = df.select_dtypes(include=['uint8']).mean(axis=1).rank(method='dense').astype('uint8')
df['quartile'] = pd.qcut(df['average_rank'], 4, labels=False)

完整链式调用示例

将以上步骤组合起来,我们就得到了一个完整的方法链:

df = (pd.read_csv('data_url')
      .rename(columns={'seek.': 'seek'})
      .rename(columns=rename_dict)
      .assign(party=lambda d: d['party'].astype('category'))
      .pipe(lambda d: d.astype({col: 'uint8' for col in d.select_dtypes(include=['int64']).columns}))
      .assign(average_rank=lambda d: d.select_dtypes(include=['uint8']).mean(axis=1).rank(method='dense').astype('uint8'),
              quartile=lambda d: pd.qcut(d['average_rank'], 4, labels=False)))

总结

本节课中我们一起学习了Pandas方法链式调用的核心概念和构建步骤。通过将多个操作连接成一条链,我们可以使代码更加简洁和逻辑清晰。虽然链式调用不是必须的,但尝试使用它可能会改变你编写数据处理代码的方式,并带来更好的可读性和维护性。Pandas是一个强大的工具,掌握其链式调用技巧将帮助你在数据工程中完成更多有趣的任务。

122:Seaborn库简介 🐍

在本节课中,我们将学习Seaborn库。Seaborn是一个基于Matplotlib和Pandas构建的优质库,它提供了一些便捷函数,用于绘制那些用其他方式实现起来可能稍显复杂的图表。

概述

上一节我们介绍了Matplotlib的基础绘图功能。本节中,我们来看看Seaborn库。Seaborn建立在Matplotlib之上,并与之深度集成,同时它也为Pandas数据结构提供了更好的支持。这意味着我们可以用更简洁的代码创建统计图形。

加载Seaborn库

要使用Seaborn,首先需要导入它。通常,我们使用import seaborn as sns来导入。这里有一个有趣的背景:sns这个别名源于美剧《白宫风云》中的一个角色Samuel Norman Seaborn,这个库正是以该角色命名的。

以下是导入Seaborn的代码:

import seaborn as sns

Seaborn的优势

因为Seaborn构建在Matplotlib之上,所以用Seaborn重现之前用Matplotlib绘制的图表相对容易。但更重要的是,Seaborn为某些我们想做的事情直接提供了接口,这使得绘制特定类型的图表变得更加简单。

你可以访问Seaborn官方网站,查看其教程文档,这些文档通常质量很高。

总结

本节课中,我们一起学习了Seaborn库的基本介绍。我们了解到Seaborn是一个基于Matplotlib和Pandas的高级可视化库,它通过提供更便捷的API简化了复杂统计图形的创建过程。在接下来的实践中,我们将用Seaborn来重现之前的图表,并体验其带来的便利性。

Python数据可视化:第3课:使用Seaborn创建折线图 🎨

在本节课中,我们将学习如何使用Seaborn库快速创建折线图。我们将重现一个关于支出的折线图,并了解Seaborn如何简化数据分组和可视化过程。


首先,我们需要加载数据。

# 假设数据已加载到名为 `df` 的DataFrame中

接下来,我们使用一行代码创建基础的折线图。

import seaborn as sns
sns.lineplot(data=df, x='Year', y='Spending', hue='Country')

通过这行代码,我们得到了一个基本的折线图。Seaborn的强大之处在于,它允许我们通过指定 hue 参数(例如按“国家”分类)来拆分数据,而无需手动进行分组操作。

如果我们设置 sort=False,折线将不会自动排序,从而可能产生回折的线条。

sns.lineplot(data=df, x='Year', y='Spending', hue='Country', sort=False)

现在,让我们尝试清理图表并使其看起来更美观。

以下是优化后的代码示例:

# 筛选特定国家并指定顺序
countries_to_plot = ['USA', 'UK', 'Germany']
palette_dict = {'USA': 'red', 'UK': 'blue', 'Germany': 'green'}

# 创建图表
ax = sns.lineplot(
    data=df[df['Country'].isin(countries_to_plot)],
    x='Year',
    y='Spending',
    hue='Country',
    hue_order=countries_to_plot,
    palette=palette_dict,
    sort=False
)

# 设置标题和Y轴范围
ax.set_title('Annual Spending by Country')
ax.set_ylim(0, None)

这段代码并非完全复现之前的内容,但你可以看到它是基于之前的图表构建的。如果需要,我们可以进一步调整参数,使其与之前的图表完全一致。

让我们简要解释一下这段代码的作用:

  1. 我们进行了一些数据筛选。
  2. 我们指定了 hue_order,这限制了图表中显示的国家。
  3. 我们指定了 palette,这是一个与 hue_order 顺序对应的颜色列表,例如我们指定美国为红色。
  4. 我们设置了标题和Y轴的范围。

至此,图表已经相当不错了。当然,我们还可以根据需求进行更多自定义。


总结

本节课中,我们一起学习了如何使用Seaborn创建折线图。我们了解到,Seaborn可以通过简单的参数(如 hue)自动处理数据分组,并通过 hue_orderpalette 等参数轻松控制图表的显示顺序和颜色。这使得创建清晰、美观的折线图变得非常高效。

124:使用Seaborn创建条形图 📊

在本节中,我们将学习如何使用Seaborn库来创建条形图。我们将使用一份经济学人风格的数据作为示例,演示如何从基础数据开始,逐步创建并定制一个条形图。通过本节的学习,你将掌握使用Seaborn的countplot函数以及如何结合Matplotlib进行深度定制。


概述

我们将使用Seaborn库来创建一个条形图。Seaborn是建立在Matplotlib之上的一个高级可视化库,它提供了更简洁的API和更美观的默认样式。我们将从一个简单的数据集开始,展示如何创建基础的条形图,并解决实际数据中可能遇到的问题,例如类别计数。最后,我们会将Seaborn的图表与纯Matplotlib的图表进行对比,展示其兼容性与定制能力。


创建基础条形图

首先,我们尝试使用Seaborn的countplot函数来为我们的数据创建条形图。countplot本质上就是Seaborn中用于绘制条形图的函数,它会自动计算每个类别的出现次数。

import seaborn as sns
import matplotlib.pyplot as plt

# 假设我们有一个包含图表类型的数据集
data = ['map', 'scatter', 'line', 'bar']
sns.countplot(x=data)
plt.show()

然而,运行上述代码可能无法得到我们期望的图表。这是因为我们的示例数据中,每个类别只出现了一次。countplot会忠实地统计每个唯一值的数量,所以每个条形的高度都是1。


处理真实世界数据

在真实场景中,数据通常包含重复的类别条目。为了模拟这种情况,我们需要创建一个包含重复项的数据集。

以下是模拟数据的示例:

import pandas as pd

# 创建一个模拟数据集,其中包含重复的类别
data = {
    'chart_type': ['map']*14 + ['scatter']*11 + ['line']*9 + ['bar']*7
}
econ_df2 = pd.DataFrame(data)

现在,如果我们对这个新的数据框使用countplot,就能得到正确的、反映每个类别总数的条形图。

sns.countplot(data=econ_df2, x='chart_type')
plt.show()

优化图表显示

默认的垂直条形图在类别标签较长时可能会产生重叠。为了解决这个问题,我们可以将条形图转换为水平方向。

以下是创建水平条形图的代码:

sns.countplot(data=econ_df2, y='chart_type')
plt.show()

水平条形图能更清晰地展示类别标签,避免重叠问题。


结合Matplotlib进行深度定制

由于Seaborn是构建在Matplotlib之上的,我们可以无缝地使用Matplotlib的函数来进一步定制图表。例如,我们可以调整坐标轴标签、标题和样式,使其与特定的出版风格(如《经济学人》)保持一致。

以下是一个结合了Seaborn绘图和Matplotlib定制的完整示例:

# 使用Seaborn创建基础图表
ax = sns.countplot(data=econ_df2, x='chart_type')

# 使用Matplotlib进行深度定制
ax.set_xlabel('')  # 将X轴标签设为空字符串
ax.set_title('Chart Type Distribution', fontsize=14)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/duke-app-py-dtengi/img/6bd3cacbeebe7a99f23d94405e3f22fb_2.png)

# 显示图表
plt.tight_layout()
plt.show()

通过这种方式,我们既利用了Seaborn快速绘图的能力,又保留了Matplotlib强大的定制灵活性。最终得到的图表在外观上可以与之前用纯Matplotlib创建的图表完全一致。


总结

在本节中,我们一起学习了如何使用Seaborn库创建条形图。我们从基础的countplot函数开始,理解了它如何处理数据。接着,我们模拟了包含重复类别的真实数据,以生成有意义的图表。然后,我们通过将条形图改为水平方向来优化其可读性。最后,我们展示了如何利用Seaborn与Matplotlib的兼容性,对图表进行深度定制,以满足特定的视觉风格要求。掌握这些技能后,你将能够高效地创建既美观又实用的数据可视化图表。

125:使用Seaborn创建散点图

在本节课中,我们将学习如何使用Seaborn库创建两种强大的散点图:lmplotjointplot。我们将使用枪支数据作为示例,演示如何通过极简的代码生成不仅包含数据点,还包含回归模型和数据分布信息的可视化图表。

使用 lmplot 创建带回归线的散点图

上一节我们介绍了Seaborn的基础。本节中我们来看看如何使用lmplot函数快速创建散点图并拟合回归模型。

lmplot是Seaborn中一个用于绘制数据并拟合回归模型的函数。其核心功能可以用以下代码描述:

sns.lmplot(x='x_column', y='y_column', data=df)

通过一行代码,我们不仅得到了数据的散点分布图,还获得了一条直观的线性回归线,帮助我们理解两个变量之间的趋势关系。

使用 jointplot 创建联合分布图

了解了带回归线的散点图后,我们来看看另一种更丰富的可视化方式——联合分布图。

jointplot可以创建散点图,并同时在坐标轴边缘添加直方图。以下是其基本调用方式:

sns.jointplot(x='x_column', y='y_column', data=df)

通过一行代码,我们得到了一个复合图表。主图是变量间的散点关系,而顶部和右侧的直方图则分别展示了每个变量的数据分布情况。这种图在Matplotlib或Pandas中实现起来较为繁琐,但Seaborn使其变得非常简单。

总结

本节课中我们一起学习了Seaborn库中两个用于创建散点图的高级函数。我们使用lmplot快速绘制了带线性回归模型的散点图,并使用jointplot生成了同时展示变量关系和各自分布的联合图。这些例子充分展示了Seaborn在简化复杂数据可视化、提升绘图效率方面的强大能力。

126:使用Seaborn创建热力图

在本节课中,我们将学习如何使用Seaborn库快速创建热力图。热力图是一种非常直观的数据可视化方式,能够清晰地展示数据矩阵中数值的分布和大小关系。我们将通过一个具体的例子,演示从加载数据到生成并美化热力图的完整过程。

加载数据

首先,我们需要加载将要使用的数据。在这个例子中,我们将使用一份总统相关的数据集。

# 假设presidential_data是已经加载好的Pandas DataFrame
import pandas as pd
# 加载数据的代码(此处为示意,具体加载方式取决于数据源)
# presidential_data = pd.read_csv('your_data.csv')

创建基础热力图

上一节我们加载了数据,本节中我们来看看如何使用Seaborn创建基础热力图。Seaborn库内置了sns.heatmap函数,这使得创建热力图变得非常简单,而无需依赖Pandas或Matplotlib的复杂操作。

以下是创建基础热力图的代码:

import seaborn as sns
import matplotlib.pyplot as plt

# 一行代码创建热力图
sns.heatmap(presidential_data)
plt.show()

执行上述代码后,将生成一个基础的热力图。需要记住的是,sns.heatmap函数的返回值是一个Matplotlib的AxesSubplot对象,这意味着我们可以像操作其他Matplotlib图表一样,对它进行各种自定义和美化。

美化热力图

基础热力图已经能够展示数据,但我们通常希望它更具可读性和美观性。接下来,我们将对图表进行一系列美化操作。

以下是美化热力图的具体步骤列表:

  1. 更改配色方案:使用cmap参数将颜色映射改为“RdBu_r”,这是一种红蓝反向的配色,能提供更好的对比。
  2. 添加数值标注:设置annot=True,在热力图的每个单元格中显示具体的数值。
  3. 设置颜色条标签:通过cbar_kws参数为颜色条添加一个描述性标签。
  4. 调整坐标轴标签:清除Y轴标签,并为图表设置一个标题。

让我们将这些步骤应用到代码中:

# 创建并美化热力图
ax = sns.heatmap(presidential_data,
                 cmap='RdBu_r',      # 使用红蓝反向配色
                 annot=True,         # 在单元格中显示数值
                 cbar_kws={'label': '数值范围'}  # 设置颜色条标签
                )

# 进一步的美化
ax.set_ylabel('')  # 清除Y轴标签
ax.set_title('总统数据热力图分析')  # 设置图表标题

plt.show()

经过美化后,我们得到了一张信息更丰富、视觉效果更好的热力图。虽然这个例子没有使用黑色背景等特定样式,但通过寥寥数行代码,我们已经能够生成一个非常实用且专业的图表。

总结

本节课中我们一起学习了如何使用Seaborn库创建和美化热力图。我们首先加载了数据,然后使用sns.heatmap函数快速生成了基础图表。最后,我们通过调整配色、添加数值标注和设置标签等步骤,显著提升了图表的可读性和专业性。掌握Seaborn的热力图功能,能让你在数据探索和展示时事半功倍。

127:使用Seaborn创建斜率图

概述

在本节课中,我们将学习如何使用Seaborn库创建斜率图。斜率图并非Seaborn内置的图表类型,但我们可以通过结合Seaborn的pointplot功能和Pandas的数据重塑功能来实现它。我们将使用Uber数据集作为示例,演示如何将数据转换为适合绘制斜率图的格式,并最终生成清晰的图表。


理解数据与问题

首先,我们查看Uber数据集。数据中包含城市、Uber使用率和私家车使用率等信息。我们的目标是创建一个斜率图,以比较不同城市在这两种交通方式上的差异。

直接使用Seaborn绘制斜率图并不直接,因为数据格式不符合pointplot函数的要求。pointplot通常需要数据以“长格式”呈现。


使用Pandas重塑数据

为了使用pointplot,我们需要将数据从“宽格式”转换为“长格式”。Pandas的melt函数非常适合完成这个任务。

以下是数据重塑的步骤:

  1. 指定保持不变的列(id_vars),这里是“city”。
  2. 其他列(‘Uber’和‘personal car’)的名称将被整合到一个名为“variable”的新列中。
  3. 这些列对应的数值将被整合到一个名为“value”的新列中。

转换后的数据结构使得每个城市都有两行数据:一行对应Uber使用率,另一行对应私家车使用率。

# 假设df是原始数据框
df_melted = df.melt(id_vars='city')

使用Seaborn绘制基础斜率图

数据重塑完成后,我们就可以使用Seaborn的pointplot函数来创建斜率图了。

以下是绘制图表的核心参数:

  • x='variable':在x轴上放置交通方式(Uber或personal car)。
  • y='value':在y轴上放置对应的使用率数值。
  • hue='city':按照城市进行分组,并用不同颜色区分。这将自动为每个城市连接其Uber和私家车的数据点,形成斜率线。

运行代码后,我们会得到一个初步的斜率图。图中每条颜色的线代表一个城市,可以直观地看到不同城市趋势的差异,例如达拉斯(Dallas)的线可能与其他城市趋势相反。

import seaborn as sns
sns.pointplot(data=df_melted, x='variable', y='value', hue='city')

优化图表样式

由于Seaborn建立在Matplotlib之上,我们可以进一步自定义图表,使其更简洁、更符合出版要求。

以下是常见的优化步骤:

  1. 移除自动生成的图例。
  2. 清除或自定义Seaborn自动添加的轴标签。
  3. 调整线条样式、标记点等。

经过这些调整,我们可以得到一个外观与定制化Matplotlib图表相似的、清晰专业的斜率图。

import matplotlib.pyplot as plt

# 绘制点图
ax = sns.pointplot(data=df_melted, x='variable', y='value', hue='city')

# 优化样式:移除图例和调整标签
ax.legend_.remove()
ax.set_xlabel('Transportation Type')
ax.set_ylabel('Usage Rate')
plt.title('Slope Chart: Uber vs Personal Car Usage by City')

plt.show()

总结

本节课中,我们一起学习了如何利用Seaborn和Pandas创建斜率图。关键步骤包括:使用melt函数将数据重塑为长格式,然后使用pointplot函数并设置hue参数按城市分组绘制连接线。最后,我们利用Matplotlib的灵活性对图表进行了样式优化。这个方法展示了如何组合不同工具来实现特定的可视化需求。

128:Matplotlib自定义指南 🎨

在本节中,我们将学习如何自定义Matplotlib图表。Matplotlib的一个强大之处在于,几乎图表的每个部分都可以根据你的需求进行调整。

上一节我们介绍了Matplotlib的基础绘图功能,本节中我们来看看如何对图表进行深度定制。

概述

在本节课中,我们将要学习如何利用Matplotlib的丰富选项来自定义图表的外观,包括颜色、样式和布局等。

自定义资源与文档

你需要了解,Matplotlib几乎允许你自定义任何元素。

我在此推荐一些速查表,建议你前往查阅。

以下是一些非常有用的速查表。

特别是这张颜色映射速查表。稍后当我们需要更改颜色映射时,你可能会需要这份关于使用何种颜色的参考,这些速查表在那时会非常有用。

总的来说,Matplotlib的官方文档非常出色。因此我建议,如果你有任何疑问,可以去官网查阅文档。文档中通常附有示例,并且你经常可以直接将这些示例复制到Jupyter中运行尝试。

总结

本节课中我们一起学习了Matplotlib图表自定义的基本理念和可用资源。我们了解到Matplotlib具有高度的可定制性,并且官方文档和社区提供的速查表是解决问题和获取灵感的重要工具。

129:文本定制详解

在本节中,我们将学习如何定制Matplotlib图表中的文本,并深入理解定制文本时涉及的各项参数和概念。我们将通过一个枪支数据的可视化案例,逐一解析文本注释、坐标定位、字体样式等核心功能。

概述

文本是数据可视化图表中传递信息的关键元素。Matplotlib提供了强大的文本定制功能,允许我们精确控制文本的位置、样式和对齐方式。掌握这些功能,可以显著提升图表的可读性和专业性。

上一节我们介绍了基础图表的绘制,本节中我们来看看如何对图表中的文本进行精细化的控制。

文本定制核心:annotate 方法

我们首先关注图表中用箭头指向的加粗文本。这是通过 annotate 方法实现的。

以下是 annotate 方法的一个关键调用示例:

ax.annotate('United States', xy=(0.03, 1), xytext=(0.03, 0.7), ...)

让我们分解这个调用中的参数:

  • 文本内容:第一个参数是字符串 'United States',即要显示的文本。
  • 箭头指向点 (xy):参数 xy=(0.03, 1) 定义了箭头所指的位置。
  • 文本位置 (xytext):参数 xytext=(0.03, 0.7) 定义了文本标签本身放置的位置。

理解坐标系统:轴分数坐标

你可能注意到 xyxytext 的值是像 (0.03, 1) 这样的小数。这代表轴分数坐标

它的含义是:

  • 将图表的X轴和Y轴范围分别归一化为 0 到 1。
  • (0, 0) 对应坐标轴的左下角。
  • (1, 1) 对应坐标轴的右上角。
  • 因此,xy=(0.03, 1) 表示箭头指向“从左边界开始3%的位置,Y轴顶部”的点。

我们通过 transform 参数来明确指定使用这种坐标系统:

transform=ax.transAxes
# 或
xycoords='axes fraction'

虽然两者字符串形式不同,但都指示Matplotlib使用轴分数坐标系。

文本样式与对齐控制

annotate 调用中,我们还可以通过其他参数精细控制文本的样式。

以下是控制文本外观的关键参数示例:

ha='left',         # 水平对齐方式:左对齐 (left)、居中 (center)、右对齐 (right)
fontsize=12,       # 字体大小
weight='bold',     # 字体粗细:加粗 (bold)
va='center',       # 垂直对齐方式:居中
arrowprops=dict()  # 用于控制箭头样式的字典
  • ha='left' 使得文本标签左对齐于 xytext 指定的位置。
  • weight='bold' 使文本显示为粗体。
  • arrowprops 是一个字典,用于定义箭头的颜色、宽度、样式等(更多细节可查阅Matplotlib文档)。

动态定位文本标签

在案例中,我们为每个数据点(国家)添加了名称标签。为了布局清晰,我们根据国家动态调整了标签位置。

以下是动态定位文本标签的逻辑代码片段:

for country in countries:
    x = data[country]['x']
    y = data[country]['y']
    if country in ['United States', 'Yemen']:
        # 对于美国和也门,将文本放在数据点左侧并右对齐
        ax.text(x - x_offset, y, country, ha='right', va='center', weight='semibold')
    else:
        # 对于其他国家,将文本放在数据点右侧并使用默认的左对齐
        ax.text(x + x_offset, y, country, va='center', weight='semibold')

这个逻辑确保了标签不会相互重叠,美国和也门的标签因数值特殊而被特意放置在左侧。

刻度标签与全局字体

除了注释和标签,图表坐标轴上的刻度文本也可以定制。

我们使用以下方法来设置刻度标签的字体和颜色:

ax.tick_params(axis='both', labelsize=10, labelcolor='gray')
# 或者通过设置全局字体属性影响刻度标签
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体
plt.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题

通过 tick_params 可以统一调整刻度标签的大小和颜色。此外,修改 rcParams 配置可以设置全局的默认字体,这也会影响刻度标签。

总结

本节课中我们一起学习了Matplotlib中文本定制的核心技巧。我们详细探讨了:

  1. 使用 annotate 方法添加带箭头的文本注释。
  2. 理解并使用轴分数坐标来精确定位文本。
  3. 通过参数控制文本的样式(大小、粗细)和对齐方式(水平、垂直)。
  4. 实现逻辑判断,为不同数据点动态调整文本标签位置以避免重叠。
  5. 定制刻度标签的样式以及设置全局字体。

你会发现,Matplotlib允许你对图表中几乎所有的文本元素进行深度定制。当你有特定需求时,查阅官方文档总是最有效的途径,你可以直接复制文档中的示例代码到Jupyter Notebook中运行和试验。

130:Matplotlib颜色定制

在本节中,我们将学习如何在Matplotlib中调整颜色,以增强图表的视觉效果和突出重点信息。

首先,我们加载数据并创建一个基础的折线图。从图中可以看到,我们使用了红色、灰色和深灰色等颜色。接下来,我们通过分析代码来理解这些颜色是如何被应用的。

颜色变量的定义与使用

在代码的开头部分,我们定义了三个颜色变量:graydark_grayred。这些变量将在后续的绘图设置中被反复调用,以确保颜色风格的一致性。

以下是定义颜色变量的代码示例:

gray = '#CCCCCC'
dark_gray = '#666666'
red = '#FF0000'

坐标轴与标签的颜色设置

上一节我们定义了颜色变量,本节中我们来看看如何将这些颜色应用到图表的各个元素上。

我们通过一个for循环,将X轴刻度颜色、Y轴刻度颜色以及坐标轴标签颜色都设置为dark_gray(深灰色)。这确保了图表中所有辅助性的文本和刻度线都使用统一的、不喧宾夺主的颜色。

以下是设置坐标轴颜色的代码:

for spine in ['xtick.color', 'ytick.color', 'axes.labelcolor']:
    plt.rcParams[spine] = dark_gray

数据线与高亮点的颜色

在绘制数据线时,我们通过plot函数中的c参数为每条线指定颜色。这是Pandas绘图接口中指定线条颜色的方式。

同时,我们还有一个逻辑:如果数据点属于美国,我们会将每第五年的标记点设置为红色。这是一种有效的高亮重要数据点的方法。

以下是绘制数据线并高亮特定点的代码:

ax.plot(data['year'], data['value'], c=country_color)
if country == 'US':
    # 高亮每第五年的数据点
    ax.scatter(data['year'][::5], data['value'][::5], c=red)

网格线与边框的颜色

为了使图表背景清晰且不干扰数据主体,我们将网格线颜色设置为浅灰色(gray)。同样,图表四周的边框(spines)也设置为相同的浅灰色。

以下是设置网格和边框颜色的代码:

ax.grid(True, color=gray, linestyle='--', linewidth=0.5)
for spine in ax.spines.values():
    spine.set_color(gray)

文本注释的颜色

最后,图表底部的图例或注释文本也使用了我们定义的dark_gray颜色,以保持整体的视觉协调性。

颜色使用的核心原则

在Matplotlib中定制颜色时,需要牢记一个核心原则:使用颜色来引导观众的视线聚焦于图表中最重要的信息

你可以通过一个简单的方法来检验颜色使用是否合理:眯起眼睛看你的图表。如果你的视线首先被吸引到的地方并非你想要强调的核心数据,那么你可能需要考虑削弱那些元素的颜色,或者直接移除它们。

公式: 有效的可视化 ≈ 突出主体 + 弱化背景


本节课中我们一起学习了如何在Matplotlib中系统化地定制颜色。我们掌握了从定义颜色变量,到将其应用于坐标轴、数据线、网格、边框及文本的完整流程。最重要的是,我们理解了颜色在数据可视化中的核心作用——即引导注意力,并学会了通过“眯眼测试”来评估颜色方案的有效性。合理运用颜色,能让你的图表传达信息时更加清晰和有力。

131:坐标轴定制与子图绘制

在本节课中,我们将学习Matplotlib中关于图形(Figure)和坐标轴(Axes)的核心概念,并重点掌握如何在一个图形中创建和定制多个坐标轴,即绘制子图。

理解子图的关键在于区分Matplotlib中的“图形”和“坐标轴”。我们可以将图形想象为绘制图表的“画纸”,而坐标轴则是画纸上一个个独立的“绘图区域”。通常,一张画纸上只有一个绘图区域,但它完全可以容纳多个。

上一节我们介绍了基础绘图,本节中我们来看看如何创建包含多个坐标轴的复杂图形。

核心概念:图形与坐标轴

以下是Matplotlib中创建图形和坐标轴的基本代码结构:

import matplotlib.pyplot as plt

# 创建一个图形(画纸)
fig = plt.figure(figsize=(8, 6))

# 在图形上添加一个坐标轴(绘图区域)
# 参数格式:[左侧起始位置,底部起始位置,宽度,高度],单位是图形尺寸的比例(0到1之间)
ax1 = fig.add_axes([0.2, 0.4, 0.8, 0.4])

这段代码创建了一个8英寸宽、6英寸高的图形,并在上面添加了一个坐标轴。该坐标轴的位置是:从图形左侧20%的位置开始,从底部40%的位置开始,宽度占图形的80%,高度占图形的40%。

多坐标轴示例:房地产市场指数图

为了更直观地理解,我们分析一个包含两个坐标轴的实际案例。下图展示了美国房地产市场指数,它实际上是一个图形包含两个坐标轴的成果。

这个图形包含两个坐标轴:

  1. 上方是一个条形图,显示主要指数。
  2. 下方是一个彩色条形图(视觉上像一条线),显示指数的月度变化。

以下是创建这个双坐标轴图形的关键代码步骤:

# 创建图形
fig = plt.figure(figsize=(8, 6))

# 添加第一个坐标轴(上方的条形图)
ax1 = fig.add_axes([0.2, 0.4, 0.8, 0.4])  # 左20%, 底40%, 宽80%, 高40%
# 在ax1上绘制条形图
ax1.bar(...)

# 添加第二个坐标轴(下方的彩色条形图)
ax2 = fig.add_axes([0.2, 0.15, 0.8, 0.1])  # 左20%, 底15%, 宽80%, 高10%
# 在ax2上绘制另一个条形图
ax2.bar(...)

通过调整 add_axes 方法中的四个比例参数,我们可以精确控制每个坐标轴在图形中的位置和大小。这为我们自由组合图表布局提供了极大的灵活性。

更多子图创建方法

除了使用 add_axes 手动指定位置,Matplotlib还提供了其他更便捷的方法来创建规则排列的子图。

以下是创建子图的几种常用方式:

  • plt.subplots: 这是最常用的方法,可以快速创建网格状排列的子图。例如,fig, axes = plt.subplots(2, 3) 会创建一个2行3列共6个子图的图形。
  • GridSpec: 提供了比 subplots 更灵活的网格划分方式,允许子图跨越多行或多列。
  • 在坐标轴内嵌套子坐标轴: 使用 inset_axes 方法可以在一个主坐标轴内部再添加一个小的坐标轴,用于放置插图或放大细节。

如果你对创建更复杂的图表布局感兴趣,建议查阅Matplotlib官方文档中关于“Subplots”和“GridSpec”的章节,那里有更详细的说明和示例。

本节课中我们一起学习了Matplotlib中图形与坐标轴的关系,并掌握了通过 add_axes 方法手动创建和定位多个坐标轴的技术。我们还了解到,除了手动布局,Matplotlib还提供了 subplotsGridSpec 等工具来高效创建规则子图。理解这些概念是进行复杂数据可视化的基础。

132:Plotly简介 🎨

在本节中,我们将学习Plotly库。Plotly是另一个可以与Pandas和Python配合使用的绘图选项。

上一节我们介绍了Matplotlib,本节中我们来看看Plotly。

Plotly与Matplotlib的区别

Matplotlib是一个非常适合制作静态图的库。什么是静态图?它是一种你希望在书籍或演示文稿中使用的图表,你可以精确调整线条、像素等所有细节。Matplotlib的不足之处在于它不太支持交互式绘图。虽然可以实现交互,但过程通常比较笨拙。这是因为Matplotlib通常在服务器进程中生成图表。例如,如果你在使用Jupyter并希望图表具有交互性,每次与网页交互时,它都需要返回服务器,生成新图表再发送回来。

为了解决这个问题,一种方法是使用JavaScript来渲染图表,这正是Plotly采用的方式。因此,Plotly使得创建交互式图表变得非常容易。然而,我发现,如果想要达到Plotly那种特定的视觉效果和最终呈现,它比Matplotlib稍微困难一些。所以,如果我想要一个非常精美的图表,我倾向于使用Matplotlib,并且直接使用Pandas内置的功能,因为它非常简单。但是,如果我需要交互性,想要深入探索数据,那么我会选择Plotly。我喜欢Plotly的一点是,它支持悬停查看数据的功能。特别是当你拥有包含大量数据的散点图时,Plotly表现得非常出色。我们稍后会看到一些例子。

总结

本节课中我们一起学习了Plotly库的基本概念及其与Matplotlib的主要区别。Plotly擅长创建交互式图表,便于数据探索;而Matplotlib则更适用于制作高度定制化的静态图表。根据你的具体需求——是追求交互性还是极致的视觉控制——可以选择合适的工具。

133:使用Plotly创建折线图 📈

在本节课中,我们将学习如何使用Plotly库来创建交互式折线图。我们将从设置绘图后端开始,逐步构建一个图表,并学习如何自定义其外观以增强可读性和信息传达。

概述

默认情况下,Pandas使用Matplotlib作为其绘图后端。如果我们希望使用Plotly来创建图表,则需要将绘图后端设置为Plotly。本教程将演示这一过程,并创建一个展示人均健康支出与预期寿命关系的折线图。

设置Plotly后端

首先,我们需要将Pandas的绘图后端从默认的Matplotlib更改为Plotly。请注意,本教程使用的是Plotly库的5.9版本。

import pandas as pd
pd.options.plotting.backend = "plotly"

加载数据并创建基础图表

上一节我们介绍了如何设置后端,本节中我们来看看如何加载数据并创建基础图表。我们加载数据,并尝试创建一个与之前用Matplotlib制作的、展示预期寿命与支出关系的类似图表。

运行代码后,因为我们已经将后端设置为Plotly,生成的图表界面看起来与之前相似,但底层已改用Plotly进行渲染。

这个图表的一个优点是具有交互性:你可以将鼠标悬停在数据点上查看具体信息。

然而,这个图表是否完美地讲述了数据故事?可能还不是。接下来,让我们看看如何清理和美化它。

自定义和美化图表

以下是用于清理和美化图表的代码。运行后,图表看起来与上面的基础版本更相似,但增加了悬停显示信息点的功能。

让我们快速浏览一下这段代码,了解其中进行的操作:

  1. 颜色映射:我们创建了一个名为 is_US 的布尔列,用于标识数据点是否属于美国。然后,我们使用 color_discrete_map 参数进行颜色映射:如果 is_US 为真(即美国的数据),则使用红色;否则使用灰色(#AAA)。
  2. 设置标签和尺寸:我们为坐标轴设置了标签(“预期寿命”和“人均健康支出”),并定义了图表的宽度和高度。
  3. 隐藏图例与调整坐标轴:我们选择不显示图例,并调整了Y轴的范围。
  4. 添加注释:通过循环,我们为每个国家的数据线添加了国家名称的注释。请注意,这里的接口与Matplotlib不同,因为Plotly并非基于Matplotlib构建,它拥有自己的一套API。
  5. 标记年份:另一个循环用于在美国的数据点上标记出对应的年份。
  6. 添加标题和刻度:最后,我们为图表添加了标题,并设置了X轴的刻度值。

最终得到的图表在视觉上相似,但由于使用了不同的库,其创建方式有所不同。

Plotly图表的一个突出优点是交互性。例如,我可以放大图表的特定区域,仔细查看这些单独的数据点。

总结

本节课中,我们一起学习了如何使用Plotly制作折线图。关键步骤包括:

  • 将Pandas的绘图后端设置为Plotly。
  • 创建基础图表的方法与使用Pandas和Matplotlib时相同。
  • 当需要自定义图表时,需要使用Plotly特有的接口进行调整,例如通过 color_discrete_map 映射颜色、添加交互式注释等。

通过Plotly,我们能够创建具有丰富交互功能的可视化图表,从而更深入地探索和展示数据。

134:使用Plotly创建条形图 📊

在本节中,我们将学习如何使用Plotly库创建条形图。我们将从加载数据开始,逐步构建一个基础条形图,然后探索如何自定义图表,例如将其转换为水平条形图并调整坐标轴标签。

概述

我们将使用Plotly的plotly.express模块来创建条形图。首先加载经济数据集,然后使用px.bar函数生成图表。之后,我们会介绍如何通过修改参数来自定义图表的外观,包括调整方向、标题和坐标轴标签。

创建基础条形图

首先,我们需要加载数据并创建一个基础的条形图。以下是实现这一步骤的代码:

import plotly.express as px

# 假设df是包含经济数据的DataFrame
fig = px.bar(df, x='type', y='count')
fig.show()

执行上述代码后,我们将看到一个垂直条形图,其中X轴代表“type”,Y轴代表“count”。

自定义条形图

在创建基础条形图后,我们可以进一步自定义它。例如,我们可以将条形图的方向从垂直改为水平,并调整标题和坐标轴标签。

以下是自定义图表的代码示例:

fig = px.bar(df, x='count', y='type', orientation='h')
fig.update_layout(
    title='经济数据统计<br>副标题',
    xaxis_title='',
    yaxis_title='',
    xaxis=dict(tickvals=[], ticktext=[]),
    yaxis=dict(tickvals=[], ticktext=[])
)
fig.show()

在这段代码中,我们通过设置orientation='h'将条形图改为水平方向。同时,我们使用HTML标签<br>在标题中插入换行,以添加副标题。为了去除X轴和Y轴的标签,我们将xaxis_titleyaxis_title设置为空字符串。此外,通过更新tickvalsticktext,我们隐藏了坐标轴上的刻度值,以避免干扰。

总结

在本节课中,我们一起学习了如何使用Plotly库创建和自定义条形图。我们从加载数据开始,创建了一个基础的垂直条形图,然后通过调整参数将其转换为水平条形图,并自定义了标题和坐标轴标签。这些步骤帮助我们更好地展示和理解数据。

135:使用Plotly创建散点图 📊

在本节课中,我们将学习如何使用Plotly库创建交互式散点图。我们将加载数据,制作基础图表,并探索如何通过添加文本标签和调整坐标轴比例来增强图表的可读性和信息量。


上一节我们介绍了Plotly的基础,本节中我们来看看如何用它制作一个散点图。

首先,加载我们的枪支数据。

# 假设 gun_data 是已加载的Pandas DataFrame
import plotly.express as px
fig = px.scatter(gun_data, x='人均枪支数', y='凶杀率')
fig.show()

生成的图表看起来与之前用Pandas制作的非常相似。

Plotly的一个优点是图表是交互式的。我们可以将鼠标悬停在数据点上以获取详细信息。

不过,您可能会注意到,悬停信息中默认不包含国家名称。也许我们想添加这个信息。

让我们看看是否能稍微调整一下图表。以下是具体做法:

fig = px.scatter(gun_data, x='人均枪支数', y='凶杀率', text='国家')
fig.update_traces(textposition='top center')
fig.show()

现在,每个数据点的上方都显示了国家标签。textposition='top center' 参数将标签置于点的正上方居中位置。

这里我还演示了一个在Matplotlib中不常见(或不易实现)的功能:将X轴和Y轴的刻度改为对数比例。

fig.update_xaxes(type="log")
fig.update_yaxes(type="log")

需要说明的是,对于当前数据,改用对数比例尺可能并不利于阐明我们想表达的观点。事实上,我认为它削弱了“美国是一个异常值”这一论点。因此,我不会在此处使用它。

但我希望您了解,有时使用对数比例尺有助于拉开数据点的间距,从而更好地观察趋势和理解数据。


本节课总结

本节课中我们一起学习了使用Plotly创建交互式散点图。我们掌握了基础绘图方法,学会了如何通过 text 参数添加数据标签,并了解了如何使用 update_xaxesupdate_yaxes 方法将坐标轴调整为对数比例。记住,图表格式的选择应服务于清晰传达数据洞察的目的。

136:使用Plotly创建热力图 📊

在本节课中,我们将学习如何使用Plotly库来创建交互式热力图。我们将加载美国总统的数据集,并生成一个可以悬停查看详细信息、缩放以及自定义样式的热力图。与Matplotlib相比,Plotly提供了更流畅的交互体验。

概述

上一节我们介绍了使用Matplotlib和Seaborn创建静态图表。本节中,我们来看看如何使用Plotly创建交互式热力图。Plotly的优势在于其丰富的交互功能,例如悬停信息提示和流畅的缩放操作,这些在Matplotlib中实现起来较为复杂。

加载数据与创建基础热力图

首先,我们需要加载数据并调用Plotly的imshow函数来创建基础热力图。这个函数与Matplotlib中的imshow功能相似,但Plotly版本支持交互。

import plotly.graph_objects as go
import pandas as pd

# 假设df是包含总统数据的DataFrame
fig = go.Figure(data=go.Heatmap(z=df.values))
fig.show()

运行上述代码会生成一个基础热力图。将鼠标悬停在热力图的单元格上,可以查看该位置的具体数值。当数据具有大量行和列时,这种交互功能尤其有用,因为它允许用户通过悬停和缩放来探索数据细节。

自定义热力图样式

为了使热力图更符合我们的展示需求,我们可以对其进行一系列自定义设置。这包括调整颜色映射、添加标题、在单元格内显示数值以及修改背景和字体颜色。

以下是自定义样式的步骤:

  1. 使用color_continuous_scale参数设置颜色映射。
  2. 通过title参数为图表添加标题。
  3. 设置text_auto=True以在热力图单元格内显示数值。
  4. 修改布局属性,如背景色、字体颜色和边距。

fig.update_layout(
    title='总统数据热力图',
    plot_bgcolor='black',
    paper_bgcolor='black',
    font_color='white',
    margin=dict(l=300)  # 设置左侧边距为300像素
)
fig.update_traces(text_auto=True)  # 在单元格内显示数值
fig.update_yaxes(title_text='排名')  # 设置Y轴标题
fig.show()

最终效果与总结

运行完整的自定义代码后,我们将得到一个样式美观、功能丰富的交互式热力图。它不仅在视觉上与我们之前用其他库创建的图表相似,而且在易用性和交互性上更胜一筹。

本节课中,我们一起学习了使用Plotly创建和自定义交互式热力图。我们了解了如何加载数据、生成基础图表,以及通过调整颜色、文本和布局来优化可视化效果。Plotly为数据探索提供了强大的交互工具,是数据工程和可视化项目中一个非常有价值的库。

137:使用Plotly创建斜率图 📈

在本节课中,我们将学习如何使用Plotly库创建一个斜率图。斜率图是一种用于比较两个时间点或两种状态下数据变化的有效图表。我们将从加载数据开始,逐步构建图表,并最终通过调整样式来突出显示关键信息。


加载与准备数据

首先,我们需要加载数据。假设我们已经有了一个包含城市和两种交通方式(如Uber和个人汽车)使用率的数据集。

import pandas as pd

# 假设df是我们的数据框
# 将‘city’列设为索引,并转置数据,以便每列代表一条线
df.set_index('city', inplace=True)
df_transposed = df.T

创建基础图表

接下来,我们使用Plotly绘制基础图表。默认情况下,Plotly会将每个列绘制为一条线,并将‘Uber’和‘个人汽车’分别放在位置0和位置1。

import plotly.graph_objects as go

fig = go.Figure()
for column in df_transposed.columns:
    fig.add_trace(go.Scatter(x=df_transposed.index, y=df_transposed[column], mode='lines+markers', name=column))

fig.show()

生成的图表看起来合理,但可能无法充分突出我们想要展示的故事。

探索条形图

通常,我们可能会使用条形图来展示这类数据。默认情况下,Plotly会生成堆叠条形图。

fig = go.Figure(data=[
    go.Bar(name='Uber', x=df_transposed.index, y=df_transposed.loc['Uber']),
    go.Bar(name='Personal Car', x=df_transposed.index, y=df_transposed.loc['Personal Car'])
])
fig.update_layout(barmode='stack')
fig.show()

然而,堆叠条形图可能无法清晰地传达我们想要的信息。我们可以通过设置barmode='group'来创建分组条形图。

fig.update_layout(barmode='group')
fig.show()

分组条形图是一个不错的图表,它展示了数据,但可能没有足够地吸引注意力到关键变化上。

构建斜率图

为了更有效地吸引注意力,我们可以创建一个斜率图。斜率图通过连接两个点的线段来强调变化。

以下是创建斜率图的步骤:

  1. 添加标记点:在数据点上添加标记,使其更明显。
  2. 设置标题和样式:添加图表标题,调整标记大小和背景颜色。
  3. 自定义坐标轴:清除不必要的坐标轴标签,并添加数据标签。
  4. 调整布局:微调X轴间距,使图表更美观。
fig = go.Figure()

# 为每个城市添加线段和标记
for city in df.index:
    fig.add_trace(go.Scatter(
        x=[0, 1],
        y=[df.loc[city, 'Uber'], df.loc[city, 'Personal Car']],
        mode='lines+markers',
        marker=dict(size=10),
        name=city
    ))

# 更新布局
fig.update_layout(
    title='交通方式使用率变化',
    plot_bgcolor='white',
    showlegend=False,
    xaxis=dict(
        title='',
        ticktext=['Uber', 'Personal Car'],
        tickvals=[0, 1],
        showgrid=False
    ),
    yaxis=dict(
        title='',
        showgrid=False,
        showticklabels=False
    )
)

# 添加数据标签
for i, city in enumerate(df.index):
    fig.add_annotation(x=0, y=df.loc[city, 'Uber'], text=f"${df.loc[city, 'Uber']}", showarrow=False, xanchor='right')
    fig.add_annotation(x=1, y=df.loc[city, 'Personal Car'], text=city, showarrow=False, xanchor='left')

fig.show()

总结

在本节课中,我们一起学习了如何使用Plotly创建斜率图。我们从加载和准备数据开始,探索了条形图作为替代方案,并最终构建了一个斜率图来更有效地展示数据变化。斜率图通过连接两个点的线段,能够突出显示变化,使观众更容易理解数据背后的故事。虽然Plotly的接口与Matplotlib不同,但它提供了强大的自定义功能,可以帮助我们创建出既美观又信息丰富的图表。

138:Dash框架简介 🚀

在本节课中,我们将学习Dash框架。Dash是一个用于构建交互式数据仪表盘的工具,由创建Plotly的团队开发,因此它与Plotly图表库有很好的集成。

什么是Dash? 📊

上一节我们介绍了Plotly,本节中我们来看看Dash。Dash是一个基于Python的开源框架,专门用于构建数据可视化Web应用。它允许数据科学家和分析师无需深入掌握前端技术(如JavaScript),就能创建出功能丰富、交互性强的仪表盘。

Dash的核心组件 ⚙️

Dash应用主要由三个核心部分组成,理解它们是构建应用的基础。

以下是Dash应用的三个核心组件:

  1. dash.Dash:这是应用的骨架。它用于初始化一个Dash应用实例,是所有组件和布局的容器。
  2. 布局(Layout):布局定义了应用在网页上的外观。它由一系列组件(如标题、图表、下拉菜单、滑块)以树状结构组成,通常使用dash.htmldash.dcc(Dash核心组件)库来构建。
  3. 回调(Callbacks):回调是Dash实现交互性的核心机制。它通过Python函数将输入组件(如下拉菜单的选择值)和输出组件(如图表的图形)连接起来。当输入发生变化时,Dash会自动调用相应的回调函数来更新输出。

一个简单的Dash应用示例 💻

为了更直观地理解,让我们通过一个最简单的“Hello World”示例来看看这些组件是如何协同工作的。

以下是创建一个基本Dash应用的代码:

# 导入必要的库
import dash
from dash import html

# 1. 初始化Dash应用
app = dash.Dash(__name__)

# 2. 定义应用的布局
app.layout = html.Div([
    html.H1('Hello Dash!'),
    html.Div('这是一个简单的Dash应用。')
])

# 3. 运行服务器
if __name__ == '__main__':
    app.run_server(debug=True)

在这段代码中:

  • dash.Dash(__name__) 创建了应用实例。
  • app.layout 使用 html.Divhtml.H1 等组件定义了网页结构。
  • app.run_server(debug=True) 启动了一个本地开发服务器。在浏览器中访问它给出的地址(通常是 http://127.0.0.1:8050),你就能看到“Hello Dash!”的页面。

Dash与Plotly的集成 📈

正如开头提到的,Dash与Plotly无缝集成。这意味着你可以轻松地将复杂的Plotly图表嵌入到Dash应用的布局中,并通过回调函数使它们根据用户输入动态更新。

以下是将Plotly图表加入Dash布局的方法:

import dash
from dash import dcc, html
import plotly.express as px
import pandas as pd

# 创建示例数据
df = pd.DataFrame({
    "Fruit": ["苹果", "橙子", "香蕉", "苹果", "橙子", "香蕉"],
    "Amount": [4, 1, 2, 2, 4, 5],
    "City": ["北京", "北京", "北京", "上海", "上海", "上海"]
})

# 创建Plotly图表
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")

# 初始化Dash应用
app = dash.Dash(__name__)

# 在布局中包含图表
app.layout = html.Div([
    html.H1('水果销量仪表盘'),
    dcc.Graph(figure=fig)  # 使用dcc.Graph组件嵌入Plotly图表
])

if __name__ == '__main__':
    app.run_server(debug=True)

总结 🎯

本节课中我们一起学习了Dash框架的基础知识。我们了解到Dash是一个强大的Python工具,用于构建交互式Web数据仪表盘。它的核心在于三个部分:应用实例(Dash)、定义界面的布局、以及实现交互逻辑的回调函数。同时,得益于其与Plotly的原生集成,我们可以便捷地将静态图表转化为可响应用户操作的动态可视化应用。掌握Dash,你就能将数据分析结果以更直观、更专业的方式呈现出来。

139:使用Dash创建折线图

在本节课中,我们将学习如何使用Dash框架创建一个简单的交互式仪表盘,并展示一个折线图。Dash是一个基于Python的Web应用框架,特别适合用于构建数据可视化界面。

概述

我们将从安装Dash开始,然后编写一个基本的脚本,该脚本会创建一个包含标题、Markdown文本和一个交互式折线图的网页。整个过程将结合Pandas进行数据处理,并使用Plotly作为绘图后端来生成图表。

安装Dash

首先,你需要安装Dash库。如果你使用Pip来管理Python包,可以通过以下命令进行安装:

pip install dash

安装完成后,你就可以开始编写Dash应用程序了。

编写基础脚本

接下来,我们创建一个Python脚本。以下是脚本的基本结构:

import dash
import pandas as pd
import plotly.express as px

# 创建Dash应用实例
app = dash.Dash(__name__)

# 设置Pandas使用Plotly作为绘图后端
pd.options.plotting.backend = "plotly"

# 使用Pandas创建示例数据并绘图
df = pd.DataFrame({
    'x': [1, 2, 3, 4, 5],
    'y': [10, 11, 12, 13, 14]
})
fig = df.plot(x='x', y='y', kind='line')

# 定义应用的布局
app.layout = dash.html.Div([
    dash.html.H1("我的第一个Dash仪表盘"),
    dash.dcc.Markdown("""
        这是一个使用**Markdown**格式的段落。
        我们可以在这里添加说明文字。
    """),
    dash.dcc.Graph(
        id='example-graph',
        figure=fig
    )
])

# 运行服务器
if __name__ == '__main__':
    app.run_server(debug=True)

代码解析

现在,让我们详细解析上面的代码。

在脚本顶部,我们导入了必要的库:dashpandasplotly.express。接着,我们创建了一个Dash应用实例。

之后,我们通过设置pd.options.plotting.backend将Pandas的绘图后端从默认的Matplotlib切换为Plotly。这意味着后续调用Pandas的.plot()方法将生成Plotly图形对象,而不是Matplotlib图形。

接下来的几行是标准的Pandas代码,用于创建一个简单的DataFrame并绘制折线图。关键点在于,.plot()方法现在返回的是一个Plotly图形对象fig

构建网页布局

在定义应用布局的部分,我们使用了Dash的HTML组件。我们添加了一个一级标题(H1)、一个Markdown组件和一个图形组件。

Markdown组件允许我们直接传入包含Markdown格式的Python字符串,Dash会自动将其渲染为HTML。图形组件则通过figure参数接收我们之前创建的Plotly图形对象fig

运行应用

在脚本的最底部,我们添加了启动开发服务器的代码。当直接运行此脚本时,Dash应用将在本地启动一个Web服务器。

要运行脚本,请在终端中执行:

python your_script_name.py

执行后,终端会输出一个本地URL(通常是http://127.0.0.1:8050)。在浏览器中打开这个URL,就能看到你的仪表盘了。

查看结果

运行上述脚本后,你将在浏览器中看到一个网页。网页顶部显示了我们添加的标题和Markdown文本。

网页下方则展示了交互式折线图。由于图表由Plotly生成,它具备丰富的交互功能:你可以用鼠标拖拽来缩放图表区域,也可以双击图表或使用工具栏的“重置轴线”按钮来恢复原始视图。

此外,因为整个仪表盘是基于HTML构建的,所以它能自适应不同的屏幕尺寸,无需手动调整图表大小。

总结

本节课中,我们一起学习了如何使用Dash创建简单的数据可视化仪表盘。我们完成了从安装Dash、编写应用脚本、设置Plotly绘图后端,到构建包含文本和交互式图表的网页布局的全过程。Dash结合Pandas和Plotly,为快速构建数据驱动的Web应用提供了一个强大而灵活的工具集。

140:使用Dash创建交互式条形图 📊

在本节课中,我们将学习如何使用Plotly和Dash创建一个带有交互式滑块的条形图。我们将看到如何将Dash组件(如滑块)与图表连接起来,从而实现数据的动态可视化更新。


概述与准备工作

上一节我们介绍了Dash应用的基本结构。本节中,我们来看看如何添加交互式控件,并让图表根据控件的值动态变化。

首先,我们需要导入必要的库。除了Dash和Plotly的核心组件,我们还需要从dash导入Input组件来创建滑块控件。

import dash
from dash import dcc, html, Input, Output
import plotly.express as px
import pandas as pd

接着,我们初始化Dash应用,并设置Pandas的绘图后端。

app = dash.Dash(__name__)
pd.options.plotting.backend = "plotly"

创建静态图表

在添加交互功能之前,我们先创建两个静态图表:一个折线图和一个条形图。以下是创建图表的代码。

# 假设df是一个包含年份('year')和数值('value')列的DataFrame
fig_line = px.line(df, x='year', y='value', title='年度趋势折线图')
fig_bar = px.bar(df, x='year', y='value', title='年度数据条形图')

构建应用布局与添加滑块

现在,我们来构建应用的网页布局。布局的核心是添加一个滑块控件,用户可以通过它选择年份。

以下是定义应用布局的代码。我们使用html.H1添加标题,用html.Br添加换行,并用dcc.Slider创建滑块。

app.layout = html.Div([
    html.H1('交互式数据仪表板'),
    html.Br(),
    dcc.Slider(
        id='year-slider',
        min=df['year'].min(),
        max=df['year'].max(),
        value=df['year'].max(),
        marks={str(year): str(year) for year in df['year'].unique()},
        step=1
    ),
    html.Br(),
    dcc.Markdown('''
        ## 图表说明
        上方滑块控制下方两个图表显示的年份范围。
    '''),
    dcc.Graph(id='line-graph', figure=fig_line),
    dcc.Graph(id='bar-graph', figure=fig_bar)
])

代码解释

  • id='year-slider':为滑块设置一个唯一ID,用于后续的回调函数连接。
  • min/max:将滑块的最小值和最大值设置为数据中的最小和最大年份。
  • value:设置滑块的初始值为最大年份。
  • marks:在滑块上显示刻度标签。
  • step=1:设置滑块每次移动的增量为1(年)。

实现交互:回调函数

为了让滑块能够控制图表,我们需要使用回调函数。回调函数是一个在输入组件值发生变化时自动被调用的函数。

我们首先创建一个更新折线图的回调函数。

@app.callback(
    Output('line-graph', 'figure'),
    Input('year-slider', 'value')
)
def update_line_figure(selected_year):
    # 根据选中的年份过滤数据
    filtered_df = df[df['year'] <= selected_year]
    # 用过滤后的数据创建新的折线图
    new_fig = px.line(filtered_df, x='year', y='value', title=f'截至 {selected_year} 年的趋势')
    return new_fig

回调机制解析

  1. @app.callback:这是一个装饰器,它定义了函数的触发条件。
  2. Output('line-graph', 'figure'):指定回调函数的输出目标是ID为line-graph的组件的figure属性。
  3. Input('year-slider', 'value'):指定回调函数的输入来源是ID为year-slider的滑块的value属性。
  4. 当滑块的值(selected_year)改变时,update_line_figure函数被调用。
  5. 函数根据传入的selected_year过滤数据,生成新的图表,并返回。Dash会自动用这个新图表更新页面上的line-graph组件。

同理,我们创建另一个回调函数来更新条形图。

@app.callback(
    Output('bar-graph', 'figure'),
    Input('year-slider', 'value')
)
def update_bar_figure(selected_year):
    filtered_df = df[df['year'] <= selected_year]
    new_fig = px.bar(filtered_df, x='year', y='value', title=f'截至 {selected_year} 年的数据')
    return new_fig

通过这两个回调函数,一个滑块就能同时控制两个图表的动态更新。


运行应用

最后,我们添加运行服务器的代码。这通常是Dash脚本的最后一部分。

if __name__ == '__main__':
    app.run_server(debug=True)

运行上述代码后,会在本地启动一个Web服务器。打开浏览器访问提供的地址(通常是 http://127.0.0.1:8050),你将看到一个包含标题、滑块、说明文字和两个图表的页面。

拖动滑块时,折线图和条形图都会实时更新,只显示从起始年份到所选年份的数据。


总结

本节课中我们一起学习了如何使用Dash创建交互式数据可视化应用。我们主要完成了以下步骤:

  1. 导入库:引入了Dash、Plotly等必要组件。
  2. 创建静态图表:使用Plotly Express生成了初始的折线图和条形图。
  3. 构建布局:设计了网页布局,并加入了关键的滑块(dcc.Slider)控件。
  4. 实现交互:通过@app.callback装饰器创建了回调函数,将滑块的输入与两个图表的输出动态绑定。

通过本教程,你掌握了将Dash控件与Plotly图表连接的核心方法,可以创建出能根据用户输入实时响应的数据仪表板。

141:使用Dash创建交互式散点图 📊

在本节课中,我们将学习如何使用Dash框架创建一个功能丰富的交互式散点图。这个图表不仅包含多个控制部件(Widgets),还能实现图表间的联动:当鼠标悬停在散点图的某个数据点上时,会自动更新页面上的其他图表以显示该点的详细信息。

概述

我们将通过一个具体示例,演示如何构建一个包含下拉菜单、单选按钮和多个关联图表的Dash应用。核心在于理解如何利用Dash的回调(Callback)机制,将用户交互(如悬停)与动态图表更新连接起来。

代码结构与解析

首先,我们导入必要的库并准备数据。

import dash
from dash import dcc, html, Input, Output
import plotly.express as px
import pandas as pd

# 使用Pandas创建示例数据框
df = pd.DataFrame(...) # 此处为数据准备代码

接下来是创建散点图的核心函数。该函数接收来自前端控件的输入参数,并返回一个配置好的散点图对象。

def create_scatter_plot(x_col, y_col, color_col, size_col, color_scale, x_scale, y_scale):
    """
    根据输入参数生成散点图。
    参数:
        x_col: X轴数据列
        y_col: Y轴数据列
        color_col: 颜色映射数据列
        size_col: 点大小映射数据列
        color_scale: 配色方案
        x_scale: X轴刻度类型(线性/对数)
        y_scale: Y轴刻度类型(线性/对数)
    """
    fig = px.scatter(df, x=x_col, y=y_col, color=color_col, size=size_col,
                     color_continuous_scale=color_scale,
                     log_x=(x_scale=='log'), log_y=(y_scale=='log'))
    return fig

应用布局设计

应用的布局定义了页面上所有可见的元素,包括各种控件和图表容器。

以下是页面布局的主要组件:

  • X轴选择下拉框:用户可以选择数据框中的任一列作为散点图的X轴。
  • Y轴选择下拉框:用户可以选择数据框中的任一列作为散点图的Y轴。
  • 颜色映射下拉框:用户可以选择一列数据,根据其值对散点图中的点进行颜色编码。
  • 点大小映射下拉框:用户可以选择一列数据,根据其值调整散点图中点的大小。
  • 配色方案下拉框:用户可以选择不同的颜色映射(如viridis, plasma, twilight等)。
  • X轴刻度单选组:用户可以选择X轴使用线性刻度还是对数刻度。
  • Y轴刻度单选组:用户可以选择Y轴使用线性刻度还是对数刻度。
  • 主散点图区域:用于显示根据上述控件配置生成的散点图。
  • 关联图表区域:包含两个图表,分别用于显示与悬停点相关的CFS(立方英尺/秒)数据和降水数据。

实现交互联动

上一节我们介绍了应用的静态布局,本节中我们来看看如何实现动态交互。这是Dash应用最强大的功能之一。

关键在于定义回调函数。以下函数定义了当鼠标在散点图上悬停时触发的动作。

@app.callback(
    [Output('cfs-graph', 'figure'),
     Output('precip-graph', 'figure')],
    [Input('main-scatter-plot', 'hoverData')]
)
def update_hover_graphs(hover_data):
    """
    根据散点图的悬停数据更新CFS和降水图表。
    参数:
        hover_data: 从散点图组件传递过来的悬停点数据
    """
    if hover_data is None:
        # 如果没有悬停数据,返回空图表
        return empty_fig, empty_fig

    # 从悬停数据中提取点的坐标
    point_index = hover_data['points'][0]['pointIndex']
    x_val = hover_data['points'][0]['x']
    y_val = df.iloc[point_index]['year'] # 假设数据中包含‘year’列

    # 根据提取的年份(或其他标识)过滤数据,生成新的图表
    filtered_df = df[df['year'] == y_val]
    new_cfs_fig = px.line(filtered_df, x='date', y='CFS')
    new_precip_fig = px.line(filtered_df, x='date', y='precipitation')

    return new_cfs_fig, new_precip_fig

这个回调函数的工作原理是:监听散点图组件的hoverData属性。一旦用户悬停,hoverData包含的信息(如点的索引、坐标值)就会作为参数传递给update_hover_graphs函数。函数处理这些数据,生成对应的新图表,并返回给页面上指定的cfs-graphprecip-graph组件,从而完成动态更新。

运行与演示

运行应用后,页面左侧是主散点图,右侧是CFS和降水趋势图。

  • 用户可以通过上方的下拉菜单和单选按钮自由调整散点图的呈现方式,例如更换X/Y轴数据、更改颜色和大小映射、切换线性/对数坐标轴。
  • 当鼠标在散点图的某个数据点上悬停时,右侧的两个趋势图会立即更新,显示与该数据点所属年份(或其他维度)相关的详细时间序列数据。
  • 例如,在一个以“月份”着色、“CFS”为Y轴的散点图中,使用循环配色方案twilight可以清晰展示河流流量随季节变化的周期性规律:浅色代表冬季(1月/12月),随着时间向夏季推进,颜色变蓝再变深,流量也呈现相应的变化趋势。

总结

本节课中我们一起学习了如何使用Dash构建一个复杂的交互式数据可视化应用。我们掌握了以下核心技能:

  1. 构建多控件界面:使用dcc.Dropdowndcc.RadioItems等组件创建用户输入界面。
  2. 创建核心图表:利用Plotly Express的px.scatter函数生成可高度定制的散点图。
  3. 实现组件回调:通过@app.callback装饰器定义函数,将用户交互(如悬停hoverData)与图表输出动态绑定。
  4. 达成图表联动:利用回调机制,使一个图表上的操作能够实时驱动其他图表的更新,从而进行深入的数据探索。

这个示例充分展示了Dash在用相对较少的代码搭建功能强大、反应迅速的交互式数据仪表盘方面的能力。通过组合不同的控件和回调逻辑,你可以为几乎任何数据分析任务创建定制化的可视化工具。

142:Streamlit简介 🚀

在本节中,我们将学习Streamlit。Streamlit是另一个用于在Python中创建仪表板的库。

概述

上一节我们介绍了使用Plotly创建交互式图表。本节中,我们来看看如何利用Streamlit库,将这些图表整合到一个功能完整的Web应用仪表板中。Streamlit简化了数据应用的构建过程,让开发者能够快速将数据脚本转化为可共享的Web应用。

什么是Streamlit?

Streamlit是一个开源的Python库,它允许数据科学家和工程师快速构建和分享美观、交互式的数据应用。你无需学习前端技术(如HTML、CSS、JavaScript),只需使用纯Python代码即可创建应用。

其核心思想是将脚本视为应用。每当你保存脚本,Streamlit应用就会自动更新,这极大地提高了开发效率。

核心概念与工作方式

Streamlit应用围绕一个脚本运行。当你运行streamlit run your_script.py命令时,会发生以下事情:

  1. Streamlit从头到尾执行你的脚本。
  2. 脚本中调用的Streamlit函数(如st.writest.dataframe)会向应用的前端界面发送指令。
  3. 每次与前端的小部件(如下拉菜单、滑块)交互时,Streamlit都会从头到尾重新执行整个脚本。

这种执行模型简单直观,但要求代码能够高效执行。对于耗时的计算,可以使用@st.cache_data装饰器进行缓存。

import streamlit as st

@st.cache_data
def load_large_dataset():
    # 这里执行耗时的数据加载操作
    data = ...
    return data

data = load_large_dataset()
st.write(data)

基本组件与用法

以下是构建Streamlit应用时最常用的一些组件。

显示文本与数据

使用st.write()可以显示几乎任何内容:文本、数据、图表。它是Streamlit中最通用的命令。

st.write("Hello, Streamlit!")
st.write(df) # 显示一个Pandas DataFrame

添加标题与标题

st.title()st.header()用于组织应用的布局结构。

st.title("我的数据分析仪表板")
st.header("第一章:销售数据概览")

创建交互式小部件

小部件允许用户与应用交互。以下是一些常用的小部件示例。

# 按钮
if st.button("点击我"):
    st.write("按钮被点击了!")

# 复选框
show_data = st.checkbox("显示原始数据")
if show_data:
    st.write(df)

# 下拉选择框
option = st.selectbox(
    "请选择一个选项:",
    ["选项A", "选项B", "选项C"]
)
st.write("你选择了:", option)

# 滑块
age = st.slider("请选择你的年龄:", 0, 100, 25)
st.write("你的年龄是:", age)

布局与容器

为了创建更复杂的布局,Streamlit提供了列和容器。

# 创建两列
col1, col2 = st.columns(2)

with col1:
    st.header("列1")
    st.line_chart([1, 2, 3, 4])

with col2:
    st.header("列2")
    st.area_chart([1, 2, 3, 4])

显示图表

Streamlit原生支持多种图表库,如Matplotlib、Plotly、Altair等。

import matplotlib.pyplot as plt
import numpy as np

# 使用Matplotlib
fig, ax = plt.subplots()
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x))
st.pyplot(fig)

# 使用Streamlit原生图表(基于Altair)
st.line_chart(df[['column_a', 'column_b']])

总结

本节课中我们一起学习了Streamlit的基础知识。我们了解到Streamlit是一个强大的Python库,能够将数据脚本快速转变为交互式Web应用。我们介绍了其核心执行模型、常用组件如文本显示、交互式小部件、布局管理以及图表集成。掌握这些基础后,你就可以开始构建自己的数据仪表板,将数据分析结果生动地呈现给他人。在接下来的课程中,我们将结合具体案例,实践如何用Streamlit构建一个完整的数据工程应用。

143:使用Streamlit创建折线图 📈

在本节课中,我们将学习如何使用Streamlit库快速创建一个交互式的折线图。Streamlit是一个强大的工具,可以让我们用简单的Python脚本构建数据应用。

概述

我们将从安装Streamlit开始,然后编写一个包含数据加载和图表创建的Python脚本。最后,我们将运行这个脚本,在浏览器中查看生成的交互式折线图。

安装Streamlit

要安装Streamlit,可以使用Pip包管理器。在命令行中执行以下命令即可完成安装。

pip install streamlit

创建并运行脚本

安装完成后,你需要编写一个Python脚本。与直接运行Python脚本不同,我们将使用Streamlit来运行它。

运行脚本时,需要使用streamlit run命令,后面跟上你的脚本文件名。执行此命令后,Streamlit会启动一个本地服务器,并自动在浏览器中打开一个页面来展示你的应用。

streamlit run your_script_name.py

构建折线图代码

现在,让我们看看如何用Streamlit制作一个折线图。以下是核心代码的结构。

在脚本顶部,我们导入必要的库,例如streamlitpandas。接着,我们使用pandas进行数据处理,这部分代码与我们之前学习的内容非常相似。

代码最有趣的部分在底部,我们使用st.line_chart()函数。这个函数会将一个折线图添加到Streamlit应用界面中。

import streamlit as st
import pandas as pd

# 使用pandas加载或创建数据
# df = pd.DataFrame(...)

# 使用Streamlit创建折线图
st.line_chart(data)

运行与交互

再次运行这个脚本。在命令行中输入streamlit run和脚本名称。

脚本运行后,浏览器中会显示我们的图表。默认情况下,这个图表是交互式的。你可以使用鼠标拖拽来平移视图,图表上方也提供了一系列工具按钮,用于进行缩放、下载图片等操作。

总结

本节课我们一起学习了使用Streamlit创建交互式折线图的全过程。我们首先安装了Streamlit库,然后编写了一个简单的脚本,利用st.line_chart()函数将pandas数据框可视化为图表,最后通过streamlit run命令在浏览器中运行并查看了这个具备平移等交互功能的图表。

144:使用Streamlit创建条形图 📊

在本节课中,我们将学习如何使用Streamlit库创建条形图。我们将从导入必要的库开始,然后使用Pandas准备数据,最后通过Streamlit的st.bar_chart函数将数据可视化。


上一节我们介绍了Streamlit的基本图表功能,本节中我们来看看如何创建条形图。

首先,我们需要导入Streamlit和Pandas库。Pandas用于数据处理,Streamlit用于构建交互式Web应用。

import streamlit as st
import pandas as pd

接下来,我们使用Pandas创建一个简单的DataFrame。这个DataFrame将作为我们图表的数据源。

data = pd.DataFrame({
    '月份': ['一月', '二月', '三月', '四月', '五月'],
    '销售额': [100, 200, 150, 400, 300]
})

数据准备完成后,我们就可以使用Streamlit来绘制图表了。Streamlit提供了多种图表函数,其中st.line_chart用于绘制折线图,st.bar_chart用于绘制条形图。

以下是绘制图表的核心代码:

st.line_chart(data.set_index('月份')['销售额'])
st.bar_chart(data.set_index('月份')['销售额'])

在这段代码中:

  1. 我们首先使用set_index('月份')将“月份”列设置为DataFrame的索引。这是为了让图表以月份作为X轴。
  2. 然后,我们选择“销售额”列作为图表的数据。
  3. 最后,分别调用st.line_chartst.bar_chart函数来生成图表。

运行上述代码后,Streamlit应用会启动。在生成的Web页面中,顶部会显示折线图,下方会显示条形图。两个图表都清晰地展示了各个月份的销售额变化趋势。


本节课中我们一起学习了使用Streamlit创建条形图的方法。我们首先导入了必要的库,然后用Pandas准备了数据,最后使用st.bar_chart函数实现了数据的可视化。通过本课,你可以掌握在Streamlit应用中快速添加条形图的基本技能。

145:在Streamlit中连接控件与图表 📊

在本节课中,我们将学习如何在Streamlit应用中,将交互式控件(如滑块)与图表(如折线图和柱状图)连接起来,实现数据的动态可视化。

概述

我们将通过一个具体的代码示例,演示如何创建一个包含年份范围滑块的Streamlit应用。当用户调整滑块时,应用中的折线图和柱状图会根据选定的年份范围实时更新。这展示了Streamlit如何简化交互式数据应用的开发流程。

代码结构与导入

首先,我们来看一下代码的基本结构。代码的开头部分导入了必要的库,并在底部定义了数据处理逻辑。

import streamlit as st
import pandas as pd
# 其他可能的导入...

数据处理与初始设置

上一节我们介绍了代码的导入部分,本节中我们来看看数据处理和初始值的设定。代码底部使用Pandas进行数据加载和计算,以确定数据集中年份的最小值和最大值。

# 假设的Pandas数据处理代码
# df = pd.read_csv(‘data.csv’)
# min_year = df[‘year’].min()
# max_year = df[‘year’].max()

添加交互式滑块控件

接下来,我们将利用计算出的最小和最大年份,在应用中添加一个滑块控件。这个滑块允许用户选择一个年份范围。

min_year = 2000  # 示例最小值
max_year = 2023  # 示例最大值

year_range = st.slider(
    ‘选择年份范围:’,
    min_value=min_year,
    max_value=max_year,
    value=(min_year, max_year)  # 设置初始值为整个范围
)

这个滑块的一个优点是,它提供了左右两个手柄,允许用户灵活地选择起始和结束年份。

将控件与图表连接

现在,我们已经有了一个可以交互的滑块。本节中,我们将看看如何利用滑块返回的数值来动态更新图表。

我们使用滑块返回的 year_range 元组(包含选定的起始和结束年份)来过滤数据,并绘制相应的图表。之前绘制静态图表的代码已被注释掉。

以下是更新后的图表绘制代码:

# 根据选定的年份范围过滤数据
# filtered_df = df[(df[‘year’] >= year_range[0]) & (df[‘year’] <= year_range[1])]

# 绘制折线图
st.line_chart(filtered_data)  # 使用过滤后的数据

# 绘制柱状图
st.bar_chart(filtered_data)  # 使用过滤后的数据

应用效果展示

让我们运行应用,看看最终效果。应用界面上方会显示渲染为HTML的Markdown文本。

界面中有一个年份范围滑块,我们可以拖动滑块的两端来调整选定的年份范围。与此同时,下方的折线图和柱状图会立即更新,只显示选定年份范围内的数据。

总结

本节课中我们一起学习了如何在Streamlit中创建交互式数据可视化应用。关键步骤包括:

  1. 导入必要的库。
  2. 计算并设置控件的参数(如最小/最大年份)。
  3. 添加交互式控件(如双柄滑块)。
  4. 将控件的返回值作为参数,动态过滤数据并更新图表。

通过这种方式,我们可以轻松构建出响应用户输入的动态数据仪表盘。

146:使用Streamlit创建交互式散点图 📊

在本节课中,我们将学习如何使用Streamlit库创建一个交互式散点图。我们将看到如何通过侧边栏的小部件(如选择框)动态控制图表的外观,例如颜色映射和显示的数据维度。


导入库与数据缓存

首先,我们需要导入必要的库。在本例中,我们使用Plotly作为绘图后端。Streamlit的一个优点是允许用户灵活选择绘图工具。

import streamlit as st
import pandas as pd
import plotly.express as px

为了提升应用性能,特别是当数据加载操作频繁但数据内容不变时,我们使用Streamlit的缓存装饰器 @st.cache_data。这可以避免每次交互都重新读取和计算数据。

@st.cache_data
def load_data():
    # 此处是加载和预处理数据的pandas代码
    # 例如:data = pd.read_csv(‘path/to/data.csv‘)
    # 返回处理好的DataFrame
    return data

git_data = load_data()

构建散点图生成函数

上一节我们设置了数据缓存,本节中我们来看看如何创建一个可配置的散点图生成函数。这个函数接收多个参数,用于控制散点图的X轴、Y轴、颜色等属性。

以下是定义该函数的代码:

def get_scatter_plot(data, x_axis, y_axis, color_by, color_map):
    """
    根据给定的参数生成一个Plotly散点图。
    参数:
        data: 包含数据的DataFrame。
        x_axis: 用于X轴的数据列名。
        y_axis: 用于Y轴的数据列名。
        color_by: 用于颜色编码的数据列名。
        color_map: 颜色映射的名称。
    返回:
        一个Plotly图形对象。
    """
    fig = px.scatter(
        data_frame=data,
        x=x_axis,
        y=y_axis,
        color=color_by,
        color_continuous_scale=color_map
    )
    return fig

创建用户界面与小部件

现在,我们开始构建Streamlit应用的用户界面。我们将使用Markdown添加标题,并在侧边栏创建一系列选择框小部件,让用户可以交互式地选择图表参数。

st.markdown(‘# 交互式散点图探索‘)

# 在侧边栏创建选择控件
with st.sidebar:
    st.header(‘图表配置‘)
    # 假设git_data DataFrame中有‘col1‘, ‘col2‘, ‘col3‘等列
    x_axis_select = st.selectbox(‘选择X轴数据:‘, options=[‘col1‘, ‘col2‘, ‘col3‘])
    y_axis_select = st.selectbox(‘选择Y轴数据:‘, options=[‘col1‘, ‘col2‘, ‘col3‘])
    color_select = st.selectbox(‘按此列着色:‘, options=[‘col1‘, ‘col2‘, ‘col3‘])
    cmap_select = st.selectbox(‘选择颜色映射:‘, options=[‘viridis‘, ‘plasma‘, ‘twilight‘, ‘rainbow‘])

生成并显示交互式图表

在配置好所有参数后,我们可以调用之前定义的函数来生成散点图,并使用 st.subheaderst.plotly_chart 将其显示在应用主区域。

st.subheader(‘生成的散点图‘)

# 调用函数生成图表
scatter_fig = get_scatter_plot(git_data, x_axis_select, y_axis_select, color_select, cmap_select)

# 在Streamlit中显示Plotly图表
st.plotly_chart(scatter_fig, use_container_width=True)

运行此应用后,你将看到一个交互式散点图。因为使用了Plotly后端,你可以对图表进行缩放、平移等操作。通过侧边栏的小部件,你可以实时更改绘制的数据维度和颜色主题。例如,将颜色映射改为‘twilight‘会得到一个循环式的颜色效果,帮助你从不同角度观察数据模式。


总结

本节课中我们一起学习了如何使用Streamlit和Plotly创建交互式散点图。关键步骤包括:

  1. 导入库并缓存数据以提升效率。
  2. 定义可配置的绘图函数,将数据与视觉参数分离。
  3. 利用Streamlit小部件构建动态控制面板。
  4. 生成并渲染交互式图表,利用Plotly的丰富功能进行数据探索。

通过结合Streamlit的简洁界面和Plotly的强大交互性,你可以快速构建用于数据分析和可视化的工具。

147:Tableau简介 🎨

在本节中,我们将学习Tableau。Tableau是一款用于创建可视化的商业产品,也被称为商业智能应用。我们可以用它来制作图表、展示图和仪表盘,并与他人分享。

概述

上一节我们介绍了数据可视化的基本概念,本节中我们来看看一个强大的可视化工具——Tableau。我们将了解它的基本功能、核心概念以及如何开始使用它来呈现数据。

Tableau是什么?

Tableau是一款商业软件,专门用于数据可视化和商业智能分析。它允许用户通过拖放界面,将复杂的数据集转化为直观的图表、图形和交互式仪表盘。

核心功能

以下是Tableau提供的一些核心功能:

  • 图表创建:支持多种图表类型,如条形图、折线图、散点图、地图等。
  • 仪表盘设计:可以将多个视图组合到一个交互式仪表盘中。
  • 数据连接:能够连接多种数据源,包括Excel、SQL数据库、云服务等。
  • 协作分享:创建的可视化成果可以轻松发布到Tableau Server或Tableau Online上,供团队协作和查看。

核心概念:工作表、仪表盘与故事

理解Tableau的三个基本构建模块至关重要:

  1. 工作表:这是创建单个视图(如图表)的地方。其核心操作是将数据字段拖放到“行”和“列”功能区来构建视图。
    • 公式示例:视图结构 ≈ 维度(行/列) + 度量(数值)。
  2. 仪表盘:这是将多个工作表组合在一起,形成统一视图的容器。你可以排列和调整各个图表,并添加筛选器等交互元素。
  3. 故事:你可以将一系列工作表或仪表盘按顺序组织起来,形成一个叙事流,用于讲述数据背后的故事。

如何开始?

对于初学者,可以按照以下步骤快速入门:

  1. 连接数据:启动Tableau后,首先连接到你的数据源(例如一个Excel文件)。
  2. 探索数据窗格:连接后,你会看到数据字段列表,它们通常被分为“维度”(分类数据)和“度量”(数值数据)。
  3. 创建第一个视图:将一个维度拖到“列”,将一个度量拖到“行”,Tableau会自动生成一个基础图表。
  4. 切换图表类型:在“标记”卡中,点击图表类型下拉菜单,可以轻松将条形图改为折线图或其他类型。
  5. 构建仪表盘:新建一个仪表盘标签页,然后将之前创建的工作表拖入其中进行布局。

总结

本节课中,我们一起学习了Tableau的基本介绍。我们了解到Tableau是一个强大的商业智能和可视化工具,它通过工作表、仪表盘和故事三个核心概念,帮助用户以直观的方式探索和展示数据。记住,其核心操作是通过拖放数据字段来构建视图。对于初学者而言,从连接数据、创建简单图表开始,是掌握Tableau的最佳途径。

148:使用Tableau创建折线图 📈

在本节课中,我们将学习如何使用Tableau软件,基于“脏魔鬼河”数据集创建一个折线图。我们将一步步地设置图表,调整数据字段,并配置坐标轴,以生成清晰的可视化结果。


上一节我们介绍了数据可视化的基本概念,本节中我们来看看如何在Tableau中具体操作。

首先,我们需要将数据导入Tableau并开始构建图表。我们的目标是创建一个折线图,其中X轴显示一年中的日期,Y轴显示河流的流量(CFS),并且希望按不同年份用颜色区分各条折线。

以下是创建折线图的具体步骤:

  1. 设置行与列:在“列”功能区中,放置“一年中的日期”字段。在“行”功能区中,放置“CFS”字段。
  2. 按年份区分颜色:将“年份”字段拖放至“颜色”标记卡上。此时,图表会开始按年份用不同颜色表示数据。
  3. 调整图表类型:初始时,图表可能显示为散点图。这是因为软件将“一年中的日期”识别为连续的数值。我们需要将其转换为离散的维度。
  4. 转换字段类型:点击“一年中的日期”字段,在下拉菜单中选择“维度”。图表将立即从散点图转变为折线图。
  5. 调整Y轴范围:为了使图表更清晰,我们可以手动设置Y轴的范围。右键点击Y轴,选择“编辑轴”。
  6. 设置固定范围:在编辑轴的对话框中,找到“范围”选项。选择“固定”模式,并将固定起始值设置为0,固定结束值设置为1000

完成以上步骤后,我们就得到了一个清晰的折线图。这个图表与我们之前在其他工具中看到的折线图效果一致,清晰地展示了不同年份下,河流流量随时间的变化趋势。


本节课中我们一起学习了在Tableau中创建折线图的完整流程。从设置行列数据、按年份区分系列,到调整字段类型和坐标轴范围,每一步都是构建有效可视化图表的关键。掌握这些基础操作后,你就能利用Tableau对数据进行初步的探索和展示了。

149:使用Tableau创建直方图 📊

在本节课程中,我们将学习如何使用Tableau软件创建一个直方图。直方图是一种用于展示数据分布情况的图表,特别适用于观察连续数据的频率分布。

概述

我们将通过一个具体的例子,演示在Tableau中从新建工作表到生成直方图的完整步骤。整个过程涉及将数据字段拖放到指定区域,并通过菜单选项调整图表类型。

创建直方图步骤

以下是创建直方图的具体操作流程。

  1. 首先,在Tableau界面中点击“新建工作表”按钮。
  2. 接着,在数据面板中找到“gauge height”(测量高度)字段,将其拖放至工作区的“列”功能区。
  3. 此时,视图区域并不会直接显示直方图。我们需要点击界面右上角的“显示我”面板。
  4. 在该面板中,找到并选择“度量”选项,然后点击其中的“直方图”图表图标。
  5. 完成上述操作后,一个直方图便成功生成了。

图表原理说明

观察生成后的工作表,可以发现Tableau自动执行了两个关键操作,其逻辑可以用以下伪代码表示:

# Tableau 创建直方图的内部逻辑示意
binned_data = bin(original_data['gauge_height']) # 将连续数据分箱
histogram_data = binned_data.value_counts() # 计算每个箱体的数据计数

具体来说,软件自动将“gauge height”字段进行了分箱处理,并在行功能区生成了“gauge height的计数”。直方图的X轴代表了分箱后的数据区间,Y轴则代表了每个区间内数据点的数量,图表由此绘制而成。

总结

本节课我们一起学习了在Tableau中创建直方图的方法。关键步骤包括:将数据字段拖入列功能区,并通过“显示我”面板选择直方图类型。Tableau会自动完成数据分箱和计数,从而直观地展示出数据的分布情况。

150:使用Tableau创建散点图

在本节课中,我们将学习如何在Tableau中创建一个散点图。散点图是一种用于展示两个连续变量之间关系的有效图表。我们将通过一个具体的例子,演示如何将数据字段从“度量”转换为“维度”,并调整坐标轴范围,以生成清晰、准确的散点图。

创建新工作表与添加字段

首先,我们需要在Tableau中创建一个新的工作表。创建完成后,我们将开始构建散点图。

以下是构建散点图的第一步操作:

  • 将“Gauge Height”(测量高度)字段拖拽到“列”功能区。
  • 将“CFS”(流量,立方英尺/秒)字段拖拽到“行”功能区。

完成上述步骤后,视图区域可能不会立即显示为预期的散点图样式。

调整字段类型以生成散点图

上一节我们添加了字段,但图表并未正确显示。这是因为Tableau默认对拖入的数值字段进行聚合计算(如求和、平均值),而散点图需要的是每个独立的数据点。

此时,我们可以尝试点击视图区上方的“散点图”图表类型按钮,但图表可能依然不正确。核心问题在于字段的聚合状态。

为了解决这个问题,我们需要进行以下操作:

  • 点击“列”功能区上“Gauge Height”字段右侧的下拉箭头(或边缘)。
  • 在弹出的菜单中,选择“维度”,将该字段从“度量”转换为“维度”。
  • 对“行”功能区上的“CFS”字段执行相同的操作,也将其转换为“维度”。

完成字段类型的转换后,视图区将正确显示为散点图,其中每个点代表一个独立的观测值。

编辑坐标轴范围

现在我们已经得到了散点图的基本形态。为了使数据分布更加清晰,我们可以手动调整坐标轴的范围。

接下来,我们将对Y轴(CFS)的范围进行设置:

  • 在散点图的Y轴(CFS轴)上右键单击。
  • 从上下文菜单中选择“编辑轴...”。
  • 在弹出的“编辑轴”对话框中,找到“范围”选项。
  • 选择“固定”模式。
  • 将固定范围的起始值设置为 0,结束值设置为 21000

通过固定坐标轴范围,我们可以确保视图聚焦在特定的数据区间内,避免因个别极端值导致图表缩放失衡,从而更准确地观察核心数据分布。

本节课中我们一起学习了在Tableau中创建散点图的完整流程。关键步骤包括:创建新工作表并放置字段、将数值字段从“度量”转换为“维度”以禁用聚合、以及通过编辑坐标轴固定范围来优化图表视图。掌握这些操作,你就能有效地利用散点图探索两个连续变量之间的关系。

151:使用Tableau创建条形图 📊

在本节课程中,我们将学习如何使用Tableau软件创建一个条形图。我们将以“每月立方英尺/秒的中位数”数据为例,演示从数据导入到图表生成的全过程。


创建新工作表

首先,我们需要在Tableau中创建一个新的工作表来放置我们的图表。


设置图表轴

接下来,我们将配置图表的横轴与纵轴。

以下是具体操作步骤:

  1. 将“月份”字段拖拽到“列”功能区。
  2. 右键点击该字段,在弹出的菜单中选择“离散”,将其设置为分类数据而非连续数据。
  3. 将“立方英尺/秒”字段拖拽到“行”功能区。

此时,图表默认对数值进行求和。


调整数值聚合方式

默认的求和方式不符合我们的需求,我们需要将其改为计算中位数。

操作方法是:点击“行”功能区上的数值字段,在下拉菜单的“度量”选项中选择“中位数”。

完成此步骤后,一个清晰的月度数据中位数条形图就生成了。


总结

本节课我们一起学习了在Tableau中创建条形图的基本流程。我们首先创建了新工作表,然后通过拖拽字段设置了图表的横纵轴,最后将数值的聚合方式从“求和”调整为“中位数”,从而得到了目标图表。

152:在Tableau中创建图表仪表板 📊

在本节课程中,我们将学习如何将Tableau中创建好的图表整合到一个统一的仪表板中,并完成发布与分享。

上一节我们介绍了如何在Tableau中制作独立的图表。本节中我们来看看如何将这些图表组合成一个功能完整的仪表板。


在Tableau工作区的底部,可以找到一个名为“仪表板”的按钮。点击此按钮,即可进入仪表板创建界面。

以下是创建仪表板的核心步骤:

  1. 添加工作表:将左侧“工作表”区域中已创建好的图表直接拖拽至右侧的仪表板画布上。或者,也可以右键点击工作表名称,然后选择“添加到仪表板”。
  2. 调整布局:在仪表板画布上,可以自由调整各图表组件的位置和大小,以优化布局。
  3. 编辑标题:如果需要,可以点击图表标题进行编辑,使其含义更清晰。
  4. 整体优化:在此阶段,可以对仪表板进行最后的清理和美化,确保其简洁直观。

完成仪表板的设计与调整后,最后一步是进行发布。

只需点击界面右上角的“发布”按钮,即可将制作好的仪表板分享给你的同事或团队成员。


本节课中我们一起学习了Tableau仪表板的创建流程:从添加图表组件、调整布局,到最终发布分享。掌握这些步骤,你就能将多个数据分析视图整合成一个有力的沟通工具。

153:Tableau功能总结 📊

在本节课中,我们将学习Tableau这一强大工具的核心功能。我们将了解它如何帮助用户轻松创建图表、汇总数据并与他人分享成果。

概述

Tableau是一款功能强大的数据可视化工具。它允许用户相对轻松地创建图表并进行数据汇总,同时也便于用户与他人分享这些可视化成果。一旦理解了数据在行、列中的组织方式以及所使用的度量标准——无论是进行聚合计算还是保持为分类数据——Tableau的使用就会变得相当简单。

核心功能解析

上一节我们概述了Tableau的基本定位,本节中我们来详细看看它的几个核心功能点。

以下是Tableau的主要功能特性:

  • 强大的可视化能力:Tableau允许用户创建各种类型的图表和图形。
  • 便捷的数据汇总:工具提供了相对简便的数据总结和聚合方法。
  • 高效的协作分享:创建的可视化成果可以轻松地与他人共享。
  • 直观的数据操作:其操作逻辑围绕数据在中的组织,以及所应用的度量方式。

关键概念:行、列与度量

理解了基本功能后,我们需要掌握其操作的核心逻辑,即数据在视图中的组织方式。

Tableau使用的关键概念包括:

  • 行(Rows)列(Columns):这定义了可视化视图的基本结构,类似于数据透视表的行轴和列轴。
  • 度量(Metrics):这是指对数据进行的计算或处理方式。它主要分为两种类型:
    1. 聚合计算:例如求和、平均值、计数等。在Tableau中,这通常通过将数值字段拖入视图并应用聚合函数(如 SUM([Sales]))来实现。
    2. 分类数据:保持数据点的离散状态,用于区分不同的类别,例如产品名称、地区等。

总结

本节课中我们一起学习了Tableau作为数据可视化工具的核心价值。我们了解到,它的强大之处在于能够通过直观地安排并选择正确的度量方式(聚合或分类),来简化图表创建、数据汇总和分享的整个过程。掌握这些基本概念是有效使用Tableau的第一步。

154:Amazon QuickSight 简介 🚀

在本节课中,我们将学习如何使用 Amazon QuickSight。Amazon QuickSight 是一个构建在 AWS 之上的商业智能套件。

概述

我们将介绍 Amazon QuickSight 的基本概念和用途。这是一个用于数据分析和可视化的强大工具。

什么是 Amazon QuickSight?

Amazon QuickSight 是一个完全托管的商业智能服务。它允许你创建和发布交互式仪表板。这些仪表板可以从任何设备访问。

核心功能

以下是 Amazon QuickSight 的一些核心功能:

  • 快速分析:它能够快速连接到你的数据源。
  • 机器学习集成:内置了机器学习功能,可以进行预测分析。
  • 按会话付费:其定价模式是基于使用量的。

工作原理

QuickSight 使用一个名为 SPICE 的内存计算引擎。SPICE 代表 Super-fast, Parallel, In-memory, Calculation Engine。它的作用是加速数据分析。

其基本工作流程可以概括为以下步骤:

  1. 连接到数据源(如 Amazon S3, RDS)。
  2. 数据被导入到 SPICE 引擎中进行高速处理。
  3. 用户通过拖拽界面创建可视化图表和仪表板。
  4. 发布和共享仪表板给团队成员。

总结

本节课我们一起学习了 Amazon QuickSight 的基本介绍。我们了解到它是一个基于 AWS 的 BI 工具,具有快速分析、机器学习集成和灵活的付费模式等特点,并通过 SPICE 引擎实现高性能数据处理。

155:在QuickSight中创建新数据集 🚀

在本节课中,我们将学习如何在亚马逊AWS的QuickSight服务中创建一个新的数据集。我们将从登录AWS开始,逐步完成数据上传和可视化的初始步骤。

概述

首先,登录到您的AWS管理控制台。登录成功后,您需要启用QuickSight服务。启用后,即可进入您的主文件夹开始操作。

创建新数据集

上一节我们完成了登录和启用服务,本节中我们来看看如何创建数据集。

在QuickSight界面中,找到并点击“数据”相关选项。以下是具体操作步骤:

  1. 定位到“数据”区域。
  2. 选择“新建数据集”选项。

上传数据文件

创建新数据集后,下一步是上传包含数据的具体文件。

我们选择通过上传文件的方式添加数据。确认文件格式无误后,即可进行上传。

数据验证与可视化

数据上传完成后,我们需要验证数据是否已被成功导入系统。

点击“可视化”按钮,系统将加载并显示我们刚刚上传的数据集内容。界面显示数据已被成功读取。

总结

本节课中我们一起学习了在AWS QuickSight中创建新数据集的完整流程。我们从登录AWS和启用QuickSight开始,逐步完成了创建数据集、上传数据文件以及进行初步数据验证和可视化的操作。

156:使用QuickSight创建折线图 📈

在本节课中,我们将学习如何在亚马逊QuickSight中创建一个折线图。我们将使用“Dirty Devil”数据集,来可视化每年中每日的立方英尺每秒流量数据。

概述

上一节我们介绍了QuickSight的基本界面。本节中,我们来看看如何创建一个具体的折线图可视化。我们将通过几个步骤来配置图表,包括选择正确的视觉类型、设置坐标轴、调整数据排序以及优化显示范围。

创建折线图

首先,我们需要在QuickSight的分析界面中添加一个新的视觉对象。

以下是创建折线图的具体步骤:

  1. 在界面顶部找到“添加”按钮,点击并选择“添加视觉对象”。
  2. 在弹出的视觉类型选择面板中,找到并点击“折线图”图标。
  3. 选择折线图后,界面右侧会显示字段井,其中包含“X轴”、“值”和“颜色”等区域。

配置图表字段

现在,我们需要将数据集中的字段拖放到对应的区域,以定义图表的结构。

以下是配置字段的步骤:

  • X轴:将“一年中的第几天”字段拖放到“X轴”区域。这决定了图表水平方向的数据点。
  • :将“立方英尺每秒”字段拖放到“值”区域。这决定了图表垂直方向,即折线的高度。
  • 颜色:将“年份”字段拖放到“颜色”区域。这会让不同年份的数据以不同颜色的折线显示。

完成初步配置后,图表已基本成型,但X轴的顺序可能不正确。

调整坐标轴与排序

观察图表,我们发现X轴(日期)的顺序有些混乱。为了解决这个问题,我们需要对X轴数据进行排序。

操作方法是点击X轴标签旁的“DOY”字段,在弹出的菜单中选择“按DOY排序”。执行此操作后,X轴上的日期将按数字顺序正确排列。

然而,图表中可能存在一些异常高的数值,导致Y轴刻度范围过大,使得主要数据区域的折线变化不明显。

优化Y轴显示范围

为了让图表更清晰地显示主要数据趋势,我们需要手动调整Y轴的范围。

以下是优化Y轴范围的步骤:

  1. 点击图表右上角的“铅笔”编辑图标。
  2. 在侧边栏的设置面板中,点击“Y轴”选项。
  3. 在Y轴设置中,找到“范围”部分,将选项从“自动”更改为“自定义范围”。
  4. 在最小值输入框中填入 0,在最大值输入框中填入 1000

经过以上调整,图表的Y轴将固定在0到1000的范围内,异常值不再影响整体视图,每条折线代表一年中每日流量的变化趋势将变得清晰可见。

总结

本节课中,我们一起学习了在QuickSight中创建折线图的完整流程。我们从添加视觉对象开始,逐步配置了X轴、值序列和颜色分组字段。接着,我们解决了X轴排序问题,并通过自定义Y轴范围优化了图表的可读性。最终,我们成功创建了一个能够清晰展示“Dirty Devil”数据集中每年日流量趋势的折线图。

157:使用QuickSight创建直方图 📊

在本节中,我们将学习如何使用Amazon QuickSight服务来创建一个直方图。直方图是一种用于展示数据分布情况的图表,特别适合观察连续变量的频率分布。

上一节我们介绍了QuickSight的基本界面,本节中我们来看看如何具体创建一个直方图可视化。

创建直方图步骤

以下是创建直方图的具体操作步骤。

  1. 首先,我们已打开目标工作表。在界面顶部找到并点击“添加”按钮,然后选择“添加视觉对象”选项。
  2. 在弹出的视觉对象类型中,我们需要选择“直方图”。
  3. 接下来,只需选择我们希望在直方图中分析的数值字段,这里我们选择“测量高度”。
  4. 完成选择后,系统会自动生成并展示“测量高度”字段的数据分布摘要,即直方图。

本节课中我们一起学习了在Amazon QuickSight中创建直方图的完整流程。从添加视觉对象到选择图表类型,再到指定分析字段,最终我们成功生成了展示“测量高度”分布的直方图。掌握这一技能有助于你快速洞察数据的分布特征。

158:使用QuickSight创建散点图 📊

在本节课程中,我们将学习如何使用亚马逊QuickSight服务创建一个散点图。我们将以“流量(立方英尺/秒)”与“水位高度”之间的关系为例,演示从添加可视化组件到配置坐标轴的完整流程。

上一节我们介绍了数据可视化工具的基本概念,本节中我们来看看如何在QuickSight中具体创建一个散点图。

创建散点图

首先,我们需要在QuickSight界面中添加一个可视化组件。具体操作是点击“添加”按钮,然后选择“添加视觉对象”。

以下是添加视觉对象的步骤:

  1. 在可视化类型中选择“散点图”。
  2. 将“水位高度”字段拖拽至X轴区域。
  3. 将“立方英尺/秒”字段拖拽至Y轴区域。

完成上述步骤后,散点图便会初步生成。此时可以观察到,图表已经根据数据自动进行了一些筛选。

理解数据筛选

生成的图表显示,它默认只展示了“立方英尺/秒”和“水位高度”两个字段中排名前50的数据点。这是一种自动的数据限制,有助于快速呈现主要的数据趋势。

因此,我们目前不需要手动调整Y轴的显示范围,因为系统已经进行了初步的筛选处理。


本节课中我们一起学习了在Amazon QuickSight中创建散点图的方法。我们掌握了添加散点图视觉对象、配置X轴与Y轴数据字段的流程,并了解了工具自动进行的数据筛选机制。

159:使用Amazon QuickSight创建条形图 📊

在本节课程中,我们将学习如何在Amazon QuickSight中创建一个条形图。我们将使用月份作为X轴,并以中位数汇总“立方英尺每秒”的数据值。


概述

首先,我们需要在QuickSight中添加一个可视化组件。我们选择添加一个条形图作为我们的视觉呈现方式。

添加并配置条形图

点击“添加”按钮以添加一个新的可视化图表。在弹出的图表类型中,我们选择“条形图”。

接下来,我们需要为图表配置数据字段。通常,当数据包含“每...”的概念时,例如“每月”,我们会将其放置在X轴上。

因此,我们将“月份”字段拖放至X轴区域。

Y轴则用于表示我们想要汇总的数值。在本例中,这个数值是“立方英尺每秒”。将其拖放至“值”区域。此时,一个基础的条形图已经生成。

为了得到更有意义的摘要数据,我们需要更改值的聚合方式。默认的聚合方式可能是求和,但我们需要的是中位数。

点击Y轴数值字段旁的聚合方式选项(通常显示为“总和”),从下拉菜单中选择“中位数”。

此外,我们注意到图表的排序方式。当前条形可能按数值大小降序排列。为了按时间顺序查看,我们需要调整排序。

点击X轴“月份”字段旁的选项,选择“按月份排序”,将图表调整为按月份升序排列。


总结

本节课中,我们一起学习了在Amazon QuickSight中创建条形图的完整步骤。关键操作包括:添加条形图视觉对象、将“月份”字段分配至X轴、将“立方英尺每秒”字段分配至Y轴并将其聚合方式改为中位数,最后将图表排序调整为按月份顺序。这个过程能帮助我们清晰地展示数据随时间变化的趋势。

160:通过QuickSight共享图表 📊

在本节课中,我们将学习如何使用Amazon QuickSight将创建的数据仪表板分享给其他人。这是一个将数据分析结果便捷地传达给团队或利益相关者的关键步骤。

上一节我们介绍了如何在QuickSight中创建和定制图表,本节中我们来看看如何将这些成果发布并共享。

发布仪表板

当你完成了想要分享的仪表板设计后,可以按照以下步骤进行发布。

以下是发布仪表板的具体操作步骤:

  1. 在仪表板界面的右上角,找到并点击“分享”按钮。
  2. 在弹出的选项中,点击“发布仪表板”。
  3. 系统会提示你为此次发布版本命名,输入一个描述性的名称。
  4. 最后,点击“发布仪表板”按钮以完成发布。

共享的优势

像Tableau和Amazon QuickSight这类商业智能工具的一大优点,就是能够轻松地将分析结果与他人共享。

这简化了协作流程,确保了所有相关人员都能基于同一份准确、可视化的数据进行决策。

本节课中我们一起学习了如何通过Amazon QuickSight发布和共享数据仪表板。你掌握了从找到分享按钮到完成发布的完整流程,并了解了这种共享方式在团队协作中的重要性。

posted @ 2026-03-26 12:26  布客飞龙III  阅读(5)  评论(0)    收藏  举报