IBM-数据科学-IV-笔记-全-

IBM 数据科学 IV 笔记(全)

001:Python数据类型入门 📊

在本节课中,我们将要学习Python中数据类型的基本概念。数据类型是Python用来表示不同种类数据的方式。理解数据类型是编写有效Python代码的基础。

概述

数据类型定义了数据的性质以及可以对数据执行的操作。Python内置了几种核心数据类型,用于处理数字、文本和逻辑值。掌握这些类型是进行数据科学、人工智能和软件开发的第一步。

数据类型简介

类型是Python表示不同数据的方式。Python中可以有不同的类型。

它们可以是像11这样的整数,像21.213这样的实数,甚至可以是单词。整数、实数和单词可以表示为不同的数据类型。

以下图表总结了上述示例对应的三种数据类型。第一列表示表达式,第二列表示数据类型。

表达式 数据类型
11 整数
21.213 浮点数
“Hello” 字符串

我们可以使用type()命令来查看Python中数据的实际类型。

type(11)      # 输出: <class 'int'>
type(21.213)  # 输出: <class 'float'>
type("Hello") # 输出: <class 'str'>

我们可以看到有int(代表整数)、float(代表浮点数,本质上是实数)和str(字符串,是字符序列)。

整数类型

整数可以是负数或正数。需要注意的是,整数的范围是有限的,但这个范围非常大。

以下是整数的一些例子:

  • -5
  • 0
  • 100

浮点数类型

浮点数是实数。它们不仅包括整数,还包括整数之间的数字。

考虑0和1之间的数字,我们可以选择它们之间的数字,这些数字就是浮点数。同样,考虑0.5和0.6之间的数字,我们也可以选择它们之间的数字,这些也是浮点数。

我们可以继续这个过程,为不同的数字“放大”观察。当然,精度存在限制,但这个限制非常小。

以下是浮点数的一些例子:

  • 3.14
  • -0.001
  • 2.0

类型转换

在Python中,你可以改变表达式的类型,这被称为类型转换

你可以将一个int转换为float。例如,你可以将整数2转换或“强制转换”为浮点数2.0。这本质上没有改变数值。

float(2) # 结果是 2.0

但是,如果将浮点数转换为整数,则必须小心。例如,如果将浮点数1.1转换为整数1,你会丢失一些信息(小数部分)。

int(1.1) # 结果是 1

字符串与其他类型的转换

如果字符串包含一个整数值,你可以将其转换为int

int("123") # 结果是整数 123

如果我们转换一个包含非整数值的字符串,就会得到一个错误。

int("123.4") # 这会引发 ValueError

你可以在实验部分查看更多例子。你也可以将int转换为str,或将float转换为str

str(123)   # 结果是字符串 "123"
str(3.14)  # 结果是字符串 "3.14"

布尔类型

布尔类型是Python中另一个重要的类型。一个布尔值可以取两个值。

第一个值是True(注意,我们使用大写字母T)。布尔值也可以是False(使用大写字母F)。

使用type()命令查看布尔值,我们得到术语bool,这是boolean的缩写。

type(True)  # 输出: <class 'bool'>
type(False) # 输出: <class 'bool'>

布尔值的转换

如果我们将布尔值True转换为整数或浮点数,会得到1

int(True)   # 结果是 1
float(True) # 结果是 1.0

如果我们将布尔值False转换为整数或浮点数,会得到0

int(False)   # 结果是 0
float(False) # 结果是 0.0

如果你将1转换为布尔值,会得到True。类似地,如果你将0转换为布尔值,会得到False

bool(1) # 结果是 True
bool(0) # 结果是 False

可以在实验部分查看更多例子,或访问Python官网(python.org)查看Python中其他类型的介绍。

总结

本节课中我们一起学习了Python的几种基本数据类型:用于整数的int、用于实数的float、用于文本的str以及用于逻辑真假的bool。我们还了解了如何使用type()函数检查类型,以及如何通过类型转换在不同类型之间进行转换。理解这些基础类型是后续学习变量、运算符和更复杂数据结构的关键。

002:表达式与变量 🧮

在本节课中,我们将要学习Python编程的两个基础概念:表达式与变量。表达式是计算机执行运算的指令,而变量则是用于存储数据值的容器。理解这两者是编写任何Python程序的第一步。

概述 📋

表达式描述了计算机执行的操作类型。变量则允许我们为数据值命名并存储它们,以便在代码中重复使用。本节将详细介绍如何创建和使用表达式与变量。


什么是表达式? 🤔

表达式是Python执行的操作。例如,基本的算术运算,如将多个数字相加。

公式示例:

40 + 60 + 60

在这个例子中,结果是160。我们称这些数字为操作数,而数学符号(本例中是加号+)称为运算符

上一节我们介绍了表达式的基本概念,本节中我们来看看Python支持的各种基本运算。

以下是Python中几种基本的算术运算:

  • 减法:使用减号-
    • 公式示例: 5 - 15 结果是 -10
  • 乘法:使用星号*
    • 公式示例: 5 * 5 结果是 25
  • 除法:使用正斜杠/
    • 公式示例: 25 / 5 结果是 5.0
    • 25 / 6 结果大约是 4.166666666666667。在我们将要使用的Python 3版本中,除法运算的结果总是浮点数
  • 整数除法:使用双斜杠//,结果会被向下取整
    • 公式示例: 25 // 6 结果是 4

请注意,在某些情况下,整数除法的结果与常规除法不同。

运算顺序 ⚖️

Python在执行数学表达式时遵循数学惯例(先乘除,后加减)。

公式示例:

1 + 2 * 3 + 4

Python会先执行乘法2 * 3得到6,然后再进行加法1 + 6 + 4,最终结果是11

我们可以使用括号()来改变运算顺序。括号内的表达式会优先计算。

公式示例:

(1 + 2) * (3 + 4)

Python会先计算(1 + 2)得到3,再计算(3 + 4)得到7,最后执行乘法3 * 7,结果是21

Python能执行的操作远不止这些。我们将在课程中学习更复杂的运算,你也可以在实验部分找到更多示例。

什么是变量? 📦

我们可以使用变量来存储值。变量就像一个贴有标签的盒子,里面可以存放数据。

代码示例:

my_variable = 1

这里,我们使用赋值运算符(即等号=)将值1赋给变量my_variable。然后,我们可以在代码的其他地方通过输入变量的确切名称来使用这个值。

我们可以使用冒号来分隔并显示变量的值(在交互式环境中常见)。

代码示例:

my_variable: 1

我们可以使用赋值运算符为my_variable赋予一个新值。

代码示例:

my_variable = 10

现在,这个变量的值变成了10。变量的旧值不再重要。

使用变量存储表达式结果 💾

我们可以存储表达式的结果。

代码示例:

x = 3 + 2 + 1

x现在存储了计算结果6

我们也可以对变量x执行操作,并将结果赋给一个新变量y

代码示例:

y = x / 3

y现在的值是2.0

我们还可以对x本身进行操作,并将新值重新赋给x

代码示例:

x = x / 3

变量x现在有了新值2.0。和之前一样,x的旧值不再重要。

我们也可以在变量上使用type()命令来查看其数据类型。

变量命名的最佳实践 ✨

为变量使用有意义的名称是一个好习惯,这样你就不必费力记住每个变量是做什么的。

假设我们想将以下音乐数据集中高亮显示的总分钟数转换为小时数。

我们称包含总分钟数的变量为total_min。通常使用下划线_来分隔单词的开头。你也可以使用大写字母(驼峰命名法)。

我们称包含总小时数的变量为total_hour

我们可以通过将total_min除以60来获得总小时数。

代码示例:

total_min = 142
total_hour = total_min / 60

结果是大约2.3666666666666667小时。

如果我们修改第一个变量(total_min)的值,依赖它的变量(total_hour)的值也会相应改变,但我们不需要修改代码的其余部分。这体现了使用变量的灵活性。


总结 🎯

本节课中我们一起学习了Python中表达式与变量的核心概念。表达式是执行计算的指令,由操作数和运算符构成。变量是存储数据的命名容器,通过赋值运算符=来创建和更新。我们了解了基本算术运算、运算顺序,以及为变量使用有意义名称的重要性。掌握这些基础知识是进行更复杂Python编程的基石。

003:字符串操作 📝

在本节课中,我们将要学习Python中字符串的基本概念和操作方法。字符串是编程中处理文本数据的基础,掌握其操作对于后续的数据处理至关重要。


什么是字符串?🔤

在Python中,字符串是一个字符序列。

一个字符串被包含在两个引号内。你也可以使用单引号。

字符串可以是空格或数字。字符串也可以是特殊字符。

我们可以将字符串绑定或赋值给另一个变量。

将字符串视为一个有序序列是有帮助的。

序列中的每个元素都可以使用由数字数组表示的索引来访问。


字符串索引与切片 🧮

我们可以像访问列表一样访问字符串中的字符。索引从0开始。

第一个索引可以如下访问:string[0]

我们可以访问索引6:string[6]

我们还可以访问第13个索引:string[12]

我们也可以对字符串使用负索引。

最后一个元素由索引-1给出:string[-1]

第一个元素可以通过索引-15获得,依此类推。

我们可以将字符串赋值给另一个变量。将字符串视为列表或元组是有帮助的。

我们可以将字符串作为序列处理并执行序列操作。

我们还可以输入一个步长值,如下所示。通过指定两个索引,我们选择每第二个变量。

我们也可以结合切片。在这种情况下,我们返回直到索引4的每第二个值。

我们可以使用len()命令来获取字符串的长度。例如,len("Hello World")的结果是11。


字符串操作:连接与复制 ➕✖️

我们可以连接或组合字符串。我们使用加号符号。

结果是一个结合了两者的新字符串。例如:"Hello" + " " + "World"

我们可以复制字符串的值。

我们只需将字符串乘以我们希望复制的次数。例如:"Hi" * 3

结果是一个新字符串。新字符串由原始字符串的三个副本组成。


字符串的不可变性 🔒

字符串是不可变的。这意味着你不能改变字符串的值,但你可以创建一个新字符串。

例如,你可以通过将其设置为原始变量并与新字符串连接来创建一个新字符串。

结果是一个从“Michael Jackson”变为“Michael Jackson is the best”的新字符串。


转义序列 ⚡

反斜杠表示转义序列的开始。

转义序列表示可能难以输入的字符串。例如,\n代表一个换行符。

输出是在遇到\n后换行。

类似地,\t代表一个制表符。输出是在\t所在位置有一个制表符。

如果你想在字符串中放置一个反斜杠,请使用双反斜杠\\

结果是一个反斜杠,在转义序列之后。

我们也可以在字符串前面放一个r,表示原始字符串,忽略转义字符。例如:r"C:\User\Name"


字符串方法 🛠️

字符串是序列,因此具有适用于列表和元组的方法。

字符串还有第二组专门用于字符串的方法。

当我们对字符串A应用一个方法时,我们会得到一个新的字符串B,它与A不同。

让我们看一些例子。


方法示例

以下是几个常用的字符串方法示例:

upper() 方法
此方法将小写字符转换为大写字符。

A = "Hello World"
B = A.upper()
# B 现在是 "HELLO WORLD"

replace() 方法
该方法将字符串的一个片段(即子字符串)替换为一个新字符串。
我们输入想要更改的字符串部分。第二个参数是我们想要用其替换该片段的内容。
结果是一个片段被更改的新字符串。

A = "Hello World"
B = A.replace("World", "Python")
# B 现在是 "Hello Python"

find() 方法
该方法查找子字符串。参数是您想要查找的子字符串。
输出是该子字符串第一次出现的索引。我们可以查找子字符串“jack”。
如果子字符串不在字符串中,则输出为-1。

A = "Michael Jackson"
index = A.find("jack")
# index 是 8(注意:Python区分大小写,'jack'和'Jack'不同)

请查看实验部分以获取更多示例。


总结 📚

本节课中我们一起学习了Python字符串的核心操作。我们了解了字符串的定义、索引与切片、连接与复制操作,以及字符串不可变的特性。我们还介绍了转义序列的用法和几个重要的字符串方法,如upper()replace()find()。理解这些基础概念是进行有效文本数据处理的关键。

004:列表与元组 📚

在本节课中,我们将学习Python中的两种复合数据类型:列表元组。它们是Python中关键的数据结构,用于存储有序的元素序列。我们将了解它们的创建、访问、操作以及它们之间的核心区别。


元组 📦

元组是一种有序序列。以下是创建一个名为ratings的元组的示例。

元组用圆括号括起来,其中的元素用逗号分隔。

括号内的这些值就是元组的元素。

ratings = (1, 2, 3, 4, 5)

在Python中,元组可以包含不同类型的元素,如字符串、整数、浮点数等。但变量本身的类型是tuple

元组的每个元素都可以通过索引来访问。

以下表格展示了索引与元组元素之间的关系。

索引 元素
0 1
1 2
2 3
3 4
4 5

第一个元素可以通过元组名称后跟方括号和索引号来访问,索引从0开始。

first_element = ratings[0] # 结果为 1

我们可以这样访问第二个元素。

second_element = ratings[1] # 结果为 2

我们也可以访问最后一个元素。

last_element = ratings[4] # 结果为 5

在Python中,我们还可以使用负索引。其对应关系如下。

负索引 正索引 元素
-5 0 1
-4 1 2
-3 2 3
-2 3 4
-1 4 5

对应的值如上所示。

last_element_negative = ratings[-1] # 结果为 5

我们可以通过相加来连接或组合元组。结果如下。

tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
combined_tuple = tuple1 + tuple2 # 结果为 (1, 2, 3, 4, 5, 6)

新元组的索引如下。

索引 元素
0 1
1 2
2 3
3 4
4 5
5 6

如果我们想从一个元组中获取多个元素,我们也可以对元组进行切片。例如,如果我们想要前三个元素,我们使用以下命令。

first_three = ratings[0:3] # 结果为 (1, 2, 3)

请注意,结束索引(3)比我们想要的最后一个元素的索引(2)大1。

类似地,如果我们想要最后两个元素,我们使用以下命令。

last_two = ratings[3:5] # 结果为 (4, 5)

请注意,结束索引(5)比元组的长度(5)大1。实际上,ratings[3:]ratings[-2:] 是更常见的写法。

我们可以使用len命令来获取元组的长度。

length = len(ratings) # 结果为 5

因为有五个元素,所以结果是5。

元组是不可变的,这意味着我们不能改变它们。为了理解为什么这很重要,让我们看看当我们将变量ratings1设置为ratings时会发生什么。

ratings = (1, 2, 3, 4, 5)
ratings1 = ratings

每个变量并不包含一个元组,而是引用了同一个不可变的元组对象。关于对象的更多信息,请参见对象和类模块。

假设我们想更改索引2处的元素,因为元组是不可变的,所以我们不能。

# ratings[2] = 99 # 这行代码会引发 TypeError

因此,ratings1不会因为ratings的改变而受到影响,因为元组是不可变的。也就是说,我们不能改变它。

我们可以为ratings变量分配一个不同的元组。

ratings = (10, 15, 20)

现在,变量ratings引用了另一个元组。

由于不可变性,如果我们想操作一个元组,我们必须创建一个新的元组。例如,如果我们想对一个元组排序,我们使用sorted函数。

sorted_ratings = sorted(ratings) # 输入是原始元组,输出是一个新的已排序列表

关于函数的更多信息,请参见我们关于函数的视频。

一个元组可以包含其他元组,以及其他复杂的数据类型。这被称为嵌套

我们可以使用标准的索引方法来访问这些元素。

NT = (1, 2, ("a", "b"), (3, ("c", "d")))

如果我们选择一个包含元组的索引,同样的索引约定也适用。因此,我们可以访问该元组中的值。例如,我们可以访问第二个元素(索引为2的元组)。

element = NT[2] # 结果为 ("a", "b")

我们可以直接将此索引应用于元组变量NT。将其可视化为一棵树会很有帮助。

我们可以将这种嵌套可视化为一棵树。该元组具有以下索引。

如果我们考虑包含其他元组的索引,我们看到索引2包含一个具有两个元素的元组。我们可以访问这两个索引。

first_in_nested = NT[2][0] # 结果为 "a"

同样的约定适用于索引3。我们也可以访问那些元组中的元素。

deep_element = NT[3][1][0] # 结果为 "c"

我们甚至可以通过添加另一个方括号来访问树的更深层次。

我们可以访问字符串中的不同字符或第二个元组中包含的各种元素。


列表 📝

列表也是Python中一种流行的数据结构。列表同样是一个有序序列。

以下是一个列表L

L = ["Michael Jackson", 10.1, 1982]

列表用方括号表示。在许多方面,列表类似于元组。一个关键区别是它们是可变的

列表可以包含字符串、浮点数、整数。我们可以嵌套其他列表。我们也可以嵌套元组和其他数据结构。对于嵌套,应用相同的索引约定。

和元组一样,列表的每个元素都可以通过索引访问。

以下表格代表了索引与列表中元素之间的关系。

索引 元素
0 "Michael Jackson"
1 10.1
2 1982

第一个元素可以通过列表名称后跟方括号和索引号来访问,索引从0开始。

first_element = L[0] # 结果为 "Michael Jackson"

我们可以这样访问第二个元素。

second_element = L[1] # 结果为 10.1

我们也可以访问最后一个元素。

last_element = L[2] # 结果为 1982

在Python中,我们可以使用负索引,其对应关系如下。

负索引 正索引 元素
-3 0 "Michael Jackson"
-2 1 10.1
-1 2 1982

对应的索引如上所示。

last_element_negative = L[-1] # 结果为 1982

我们也可以在列表中进行切片。例如,如果我们想要这个列表中的最后两个元素,我们使用以下命令。

last_two_elements = L[1:3] # 结果为 [10.1, 1982]

请注意,结束索引(3)比列表的长度(3)大1。列表和元组的索引约定是相同的。更多示例请查看实验部分。

我们可以通过相加来连接或组合列表。结果如下。

L1 = ["Michael Jackson", 10.1]
L2 = [1982]
L3 = L1 + L2 # 结果为 ["Michael Jackson", 10.1, 1982]

新列表具有以下索引。

列表是可变的。因此,我们可以改变它们。例如,我们应用extend方法,通过添加一个点后跟方法名,然后是括号。括号内的参数是我们要连接到原始列表的新列表。

L = ["Michael Jackson", 10.1]
L.extend([1982, "Thriller"])
# 现在 L 变为 ["Michael Jackson", 10.1, 1982, "Thriller"]

在这种情况下,不是创建一个新列表L1,而是通过添加两个新元素来修改原始列表L。要了解更多关于方法的信息,请查看我们关于对象和类的视频。

另一个类似的方法是append。如果我们应用append而不是extend,我们向列表中添加一个元素。

L = ["Michael Jackson", 10.1, 1982]
L.append(["Thriller"])
# 现在 L 变为 ["Michael Jackson", 10.1, 1982, ["Thriller"]]

如果我们查看索引,只多了一个元素。索引3包含我们追加的列表。

每次我们应用一个方法,列表都会改变。如果我们应用extend,我们向列表添加两个新元素。列表L通过添加两个新元素被修改。

如果我们追加字符串"A",我们进一步改变列表,添加了字符串"A"

由于列表是可变的,我们可以改变它们。例如,我们可以如下更改第一个元素。

L[0] = "hard rock"
# 现在列表变为 ["hard rock", 10.1, 1982]

我们可以使用del命令删除列表的一个元素。我们只需将要删除的列表项作为参数指明。例如,如果我们想删除第一个元素。

del(L[0])
# 结果变为 [10.1, 1982]

我们可以删除第二个元素。此操作会移除列表的第二个元素。

我们可以使用split将字符串转换为列表。例如,split方法将以空格分隔的每组字符转换为列表的一个元素。

string = "A,B,C,D"
result_list = string.split(",") # 结果为 ["A", "B", "C", "D"]

我们可以使用split函数在特定字符(称为分隔符)上分隔字符串。我们只需传递我们想要分割的分隔符作为参数。在这种情况下是逗号。结果是一个列表。每个元素对应一组被逗号分隔的字符。

当我们设置一个变量B等于A时,AB都引用同一个列表。多个名称引用同一个对象被称为别名

A = ["hard rock", 10, 1.2]
B = A

我们从列表的幻灯片中知道,B中的第一个元素被设置为"hard rock"。如果我们将A中的第一个元素改为"banana",会产生副作用。B的值也会随之改变。

A[0] = "banana"
print(B[0]) # 输出 "banana" 而不是 "hard rock"

AB引用同一个列表,因此,如果我们改变A,列表B也会改变。如果在更改列表A后检查B的第一个元素,我们得到的是"banana"而不是"hard rock"

你可以使用以下语法克隆列表A

A = ["hard rock", 10, 1.2]
B = A[:] # 创建 A 的一个新副本

变量A引用一个列表。变量B引用原始列表的一个新副本或克隆。现在,如果你改变AB不会改变。

我们可以使用help命令获取关于列表、元组和Python中许多其他对象的更多信息。只需传入列表、元组或任何其他Python对象。

help(list)
help(tuple)

更多关于列表的操作,请参见实验部分。


总结 ✨

在本节课中,我们一起学习了Python中两个重要的复合数据类型:元组列表

  • 元组:使用圆括号()定义,是不可变的有序序列。这意味着一旦创建,其内容无法更改。它们适用于存储不应被修改的数据集合。
  • 列表:使用方括号[]定义,是可变的有序序列。这意味着创建后,可以对其内容进行添加、删除或修改。它们功能更灵活,是编程中最常用的数据结构之一。

我们掌握了如何创建它们、通过索引和切片访问元素、进行连接操作,并理解了可变性与不可变性的核心区别及其影响(如别名问题)。我们还简要了解了嵌套结构和一些实用的方法(如split, append, extend)。

理解列表和元组是有效组织和管理数据的基础,对于后续学习更复杂的数据结构和进行数据分析至关重要。

005:Python字典结构 📚

在本节课中,我们将要学习Python中的字典结构。字典是Python中一种重要的集合类型,它通过键值对来存储和访问数据。我们将从字典的基本概念开始,逐步学习如何创建、访问、修改字典,以及如何使用字典的常用方法。


字典的基本概念 🔑

上一节我们介绍了列表,列表使用整数索引来访问元素。本节中我们来看看字典,它与列表类似,但使用键来访问值。

字典由键和值组成。键类似于列表的索引,但键不一定是整数,通常是字符串。值则类似于列表中的元素,用于存储具体信息。

以下是字典的核心概念公式:

  • 字典结构{key1: value1, key2: value2, ...}
  • 访问值dict_name[key]

创建字典 ➕

要创建一个字典,我们使用花括号 {}。键是第一个元素,必须是不可变且唯一的。每个键后面跟着一个冒号 :,然后是值。值可以是任何类型的数据,并且允许重复。每个键值对之间用逗号 , 分隔。

考虑以下字典示例,其中专辑名称是键,发行年份是值:

# 创建一个字典
album_release_dates = {
    "Back in Black": 1980,
    "The Dark Side of the Moon": 1973,
    "The Bodyguard": 1992
}

我们可以将字典想象成一个表格,第一列是键,第二列是对应的值。


访问与修改字典 🔄

我们可以通过键来访问字典中的值,使用方括号 [],括号内的参数是键。这会返回对应的值。

以下是访问字典值的示例:

# 访问值
print(album_release_dates["Back in Black"])  # 输出:1980
print(album_release_dates["The Dark Side of the Moon"])  # 输出:1973

我们可以向字典中添加新的条目,方法是为一个新的键赋值。

# 添加新条目
album_release_dates["Graduation"] = 2007

我们也可以删除字典中的条目,使用 del 语句。

# 删除条目
del album_release_dates["The Bodyguard"]


字典的常用操作 🛠️

我们可以使用 in 命令来检查某个键是否存在于字典中。这个命令会检查键,如果键在字典中,则返回 True,否则返回 False

以下是检查键是否存在的示例:

# 检查键是否存在
print("Thriller" in album_release_dates)  # 输出:False
print("Back in Black" in album_release_dates)  # 输出:True

为了获取字典中所有的键,我们可以使用 .keys() 方法。其输出是一个类似列表的对象,包含所有键。

同样地,我们可以使用 .values() 方法来获取字典中所有的值。

以下是获取所有键和值的示例:

# 获取所有键
keys = album_release_dates.keys()
print(keys)  # 输出类似:dict_keys(['Back in Black', 'The Dark Side of the Moon', 'Graduation'])

# 获取所有值
values = album_release_dates.values()
print(values)  # 输出类似:dict_values([1980, 1973, 2007])


总结 📝

本节课中我们一起学习了Python字典结构。我们了解了字典由键值对组成,学会了如何使用花括号创建字典,如何通过键访问和修改值,以及如何使用 in 命令、.keys().values() 方法来操作字典。字典是存储和快速查找关联数据的强大工具,请在实验环节查看更多示例以加深理解。

006:集合类型详解

在本节课中,我们将学习Python中的集合类型。集合是一种无序且元素唯一的容器,与列表和元组不同,它不记录元素位置。我们将介绍如何创建集合、进行类型转换,以及执行常见的集合操作。


🧩 什么是集合?

集合是一种容器类型。这意味着,与列表和元组类似,你可以在集合中存放不同的Python数据类型。

与列表和元组不同,集合是无序的。这意味着集合不记录元素的位置。

集合只包含唯一元素。这意味着在集合中,每个特定元素只出现一次。


🔧 创建集合

要定义一个集合,需使用花括号。将集合的元素放在花括号内。

# 示例:创建集合
my_set = {1, 2, 3, 'apple', 'banana'}

你可能会注意到存在重复项。当实际创建集合时,重复项将不会出现。


🔄 列表转换为集合

你可以使用set()函数将列表转换为集合。这称为类型转换。

你只需将列表作为set()函数的输入参数。结果将是一个由列表转换而来的集合。

# 示例:将列表转换为集合
my_list = [1, 2, 2, 3, 'apple', 'apple']
my_set = set(my_list)
# 结果:{1, 2, 3, 'apple'}

注意转换后没有重复元素。


🛠️ 集合操作

这些操作用于修改集合。考虑集合A,我们可以用一个圆圈来表示它。如果你熟悉集合,这可以是维恩图的一部分。

维恩图是一种使用形状(通常是圆形)来表示集合的工具。


添加元素

我们可以使用add()方法向集合中添加一个元素。只需在集合名称后加点号,然后调用add()方法。参数是我们要添加的新元素。

# 示例:向集合添加元素
set_A = {1, 2, 3}
set_A.add(4)
# 结果:{1, 2, 3, 4}

如果添加相同的元素两次,不会发生任何变化,因为集合中不能有重复项。


移除元素

我们可以使用remove()方法从集合中移除一个元素。只需在集合名称后加点号,然后调用remove()方法。参数是我们要移除的元素。

# 示例:从集合移除元素
set_A = {1, 2, 3, 4}
set_A.remove(4)
# 结果:{1, 2, 3}

应用remove()方法后,集合A不再包含该元素。你可以对集合中的任何元素使用此方法。


检查元素是否存在

我们可以使用in命令来验证一个元素是否在集合中。

# 示例:检查元素是否在集合中
set_A = {1, 2, 3}
print(2 in set_A)  # 输出:True
print(5 in set_A)  # 输出:False

该命令检查指定项是否在集合中。如果存在,则返回True;如果不存在,则返回False


➕ 集合的数学运算

我们可以在集合之间进行许多有用的数学运算。

让我们定义集合album_set1。我们可以用一个红色圆圈或维恩图来表示它。

类似地,我们可以定义集合album_set2。我们也可以用一个蓝色圆圈或维恩图来表示它。


交集

两个集合的交集是一个新集合,包含同时存在于这两个集合中的元素。使用维恩图有助于理解。代表两个集合的圆圈合并,重叠部分代表新集合。

在Python中,我们使用&符号来求两个集合的交集。

# 示例:求两个集合的交集
album_set1 = {'AC/DC', 'Back in Black', 'Thriller'}
album_set2 = {'AC/DC', 'Back in Black', 'The Dark Side of the Moon'}
album_set3 = album_set1 & album_set2
# 结果:{'AC/DC', 'Back in Black'}

应用交集操作后,所有不同时存在于两个集合中的项都会消失。


并集

两个集合的并集是一个新集合,包含两个集合中的所有元素。

我们可以如下找到集合album_set1album_set2的并集:

# 示例:求两个集合的并集
album_set1 = {'AC/DC', 'Back in Black', 'Thriller'}
album_set2 = {'AC/DC', 'Back in Black', 'The Dark Side of the Moon'}
union_set = album_set1 | album_set2
# 结果:{'AC/DC', 'Back in Black', 'Thriller', 'The Dark Side of the Moon'}

结果是一个包含album_set1album_set2所有元素的新集合。


子集检查

考虑新集合album_set3。该集合包含元素AC/DCBack in Black。我们可以用维恩图表示,因为album_set3的所有元素都在album_set1中。

我们可以使用issubset()方法检查一个集合是否是另一个集合的子集。

# 示例:检查子集关系
album_set1 = {'AC/DC', 'Back in Black', 'Thriller'}
album_set3 = {'AC/DC', 'Back in Black'}
print(album_set3.issubset(album_set1))  # 输出:True

由于album_set3album_set1的子集,结果为True


📝 总结

在本节课中,我们一起学习了Python中的集合类型。我们了解了集合是无序且元素唯一的容器,学会了如何创建集合、将列表转换为集合,以及执行添加、移除、检查元素存在性等基本操作。我们还探讨了集合的数学运算,包括交集、并集和子集检查。集合是处理唯一数据集时的强大工具,在数据科学和AI应用中非常有用。

007:条件判断与分支 🧠

在本节课中,我们将要学习Python中的条件判断分支。这是编程中控制程序流程的基础,允许程序根据不同的情况执行不同的代码块。

概述 📋

条件判断通过比较操作来评估表达式,并根据结果是真(True)还是假(False)来决定程序的执行路径。我们将学习比较运算符、ifelseelif语句,以及逻辑运算符。


比较运算符 🔍

比较运算符用于比较两个值,并返回一个布尔值(TrueFalse)。

以下是Python中常用的比较运算符:

  • 等于==
  • 不等于!=
  • 大于>
  • 小于<
  • 大于等于>=
  • 小于等于<=

等于运算符(==

等于运算符(==)检查两个值是否相等。

a = 6
print(a == 7)  # 输出:False
print(a == 6)  # 输出:True

大于运算符(>

大于运算符(>)检查左侧操作数的值是否大于右侧操作数的值。

i = 6
print(i > 5)  # 输出:True

如果我们将i的值设为2,结果将是False

大于等于运算符(>=

大于等于运算符(>=)检查左侧操作数的值是否大于或等于右侧操作数的值。

i = 5
print(i >= 5)  # 输出:True

小于运算符(<

小于运算符(<)检查左侧操作数的值是否小于右侧操作数的值。

i = 2
print(i < 6)  # 输出:True

不等于运算符(!=

不等于运算符(!=)检查两个操作数是否不相等。

i = 2
print(i != 6)  # 输出:True

字符串比较

比较运算符也可以用于比较字符串。

print(“ACDC” == “Michael Jackson”)  # 输出:False
print(“ACDC” != “Michael Jackson”)  # 输出:True

分支语句:if 🚪

上一节我们介绍了如何使用比较运算符得到布尔值。本节中我们来看看如何利用这些布尔值来控制程序流程,这称为分支

if语句就像一个上锁的房间。只有当条件为True时,程序才能“进入房间”执行预定义的任务。如果条件为False,程序会跳过这个任务。

语法

if (条件表达式):
    # 如果条件为True,则执行此缩进块内的代码

示例:模拟音乐会年龄检查

age = 19
if (age >= 18):
    print(“你可以入场。”)
print(“继续流程。”)

age为19时,条件为True,程序会打印“你可以入场。”,然后打印“继续流程。”。
age为17时,条件为False,程序只会打印“继续流程。”。


分支语句:else 🔄

else语句与if语句配合使用,当if的条件为False时,程序会执行else块中的代码。

语法

if (条件表达式):
    # 条件为True时执行
else:
    # 条件为False时执行

示例:为不同年龄提供不同音乐会选项

age = 17
if (age >= 18):
    print(“你可以进入ADC音乐会。”)
else:
    print(“你可以去 Meatloaf 音乐会。”)
print(“继续流程。”)

age为17时,if条件为False,程序执行else块,打印“你可以去 Meatloaf 音乐会。”。
age为19时,if条件为True,程序执行if块,打印“你可以进入ADC音乐会。”,并跳过else块。


分支语句:elif(else if)🎯

elif语句(else if的缩写)允许我们在前面的条件为False时,检查额外的条件。

语法

if (条件1):
    # 条件1为True时执行
elif (条件2):
    # 条件1为False 且 条件2为True时执行
else:
    # 以上条件都为False时执行

示例:为18岁观众提供特别选项

age = 18
if (age > 18):
    print(“你可以进入ADC音乐会。”)
elif (age == 18):
    print(“你可以去看 Pink Floyd 音乐会。”)
else:
    print(“你可以去 Meatloaf 音乐会。”)
print(“继续流程。”)

age为18时,第一个条件(age > 18)为False,程序检查elif条件(age == 18)为True,因此打印“你可以去看 Pink Floyd 音乐会。”。


逻辑运算符 🧩

逻辑运算符用于组合多个布尔表达式,形成更复杂的条件。

逻辑非(not

not运算符对布尔值取反。如果输入是True,结果为False;如果输入是False,结果为True

print(not(True))   # 输出:False
print(not(False))  # 输出:True

逻辑或(or

or运算符接受两个布尔值,只要其中至少有一个True,结果就为True;只有两者都为False时,结果才为False

A B A or B
True True True
True False True
False True True
False False False

示例:检查专辑年份是否为70年代或90年代

album_year = 1990
if (album_year < 1980) or (album_year > 1989):
    print(“这张专辑制作于70年代或90年代。”)
else:
    print(“这张专辑制作于80年代。”)

对于album_year = 1990,第二个条件(1990 > 1989)为True,因此整个or表达式为True,会执行if块内的打印语句。

逻辑与(and

and运算符接受两个布尔值,只有两者都为True时,结果才为True;否则结果为False

A B A and B
True True True
True False False
False True False
False False False

示例:精确检查专辑年份是否为80年代

album_year = 1983
if (album_year > 1979) and (album_year < 1990):
    print(“这张专辑制作于80年代。”)

对于album_year = 1983,两个条件(1983 > 19791983 < 1990)都为True,因此整个and表达式为True,会执行if块内的打印语句。


总结 🎓

本节课中我们一起学习了Python中控制程序流程的核心概念:

  1. 比较运算符==, !=, >, <, >=, <=)用于评估条件并产生布尔值。
  2. if语句用于在条件为True时执行特定代码块。
  3. else语句if配对,在if条件为False时提供替代执行路径。
  4. elif语句允许在if条件不满足时,顺序检查多个条件。
  5. 逻辑运算符not, and, or)用于组合多个布尔条件,构建更复杂的逻辑判断。

掌握条件判断和分支是编写智能、动态程序的基础,它让你的代码能够根据不同的输入和数据做出决策。

008:循环结构 🔄

在本节课中,我们将学习Python中的循环结构,特别是for循环while循环。我们将通过直观的示例来理解它们的工作原理,并学习如何使用range函数和enumerate函数来辅助循环操作。掌握循环是自动化重复任务的关键,对于数据处理和算法实现至关重要。


🔢 range函数简介

在深入讨论循环之前,我们先来了解一个重要的内置函数:rangerange函数用于生成一个有序的数字序列。

  • 如果只提供一个正整数参数nrange(n)会生成一个从0开始,到n-1结束的序列。例如,range(3)生成序列[0, 1, 2]
  • 如果提供两个参数startstoprange(start, stop)会生成一个从start开始,到stop-1结束的序列。例如,range(10, 15)生成序列[10, 11, 12, 13, 14]

请注意,在Python 3中,range函数生成的是一个“range对象”,它按需生成值,而不是像Python 2那样直接生成一个完整的列表,这在处理大范围数字时更高效。


🔁 For循环

上一节我们介绍了range函数,本节中我们来看看最常用的循环结构——for循环。我们将以列表为例,但许多操作同样适用于元组。

循环的核心作用是重复执行某项任务。设想有一组彩色方块,我们想将每个方块都替换成白色方块。

为了便于操作,我们给每个方块编号,并将这组方块称为squares列表。在Python中,我们可以用列表来表示这些方块,列表中的每个元素是一个代表颜色的字符串。我们的目标是将每个元素的值改为"white"

以下是使用range函数和索引进行for循环的语法:

squares = ['red', 'yellow', 'green', 'purple', 'blue']

for i in range(5):
    squares[i] = "white"

代码解析:

  • range(5)生成序列[0, 1, 2, 3, 4]
  • 循环会重复执行缩进块内的代码5次。
  • 每次循环,变量i的值依次为0, 1, 2, 3, 4。
  • 在每次迭代中,我们将列表squares的第i个元素设置为"white"

直接迭代列表元素

我们也可以不通过索引,直接迭代列表或元组中的每一个元素。

squares = ['red', 'yellow', 'green']

for square in squares:
    print(square)

循环过程:

  • 第一次迭代:变量square的值为'red'
  • 第二次迭代:变量square的值为'yellow'
  • 第三次迭代:变量square的值为'green'

使用enumerate函数同时获取索引和元素

有时我们需要在循环中同时获得元素的索引和值,这时enumerate函数就非常有用。

其语法如下:

squares = ['red', 'yellow', 'green']

for i, square in enumerate(squares):
    print(f"Index {i} is {square}")

循环过程:

  • 第一次迭代:i = 0, square = 'red'
  • 第二次迭代:i = 1, square = 'yellow'
  • 第三次迭代:i = 2, square = 'green'

⏱️ While循环

for循环用于执行已知次数的重复任务,而while循环则用于在某个条件为真时,持续执行代码块。

设想一个场景:我们想从一个方块列表中复制所有橙色方块到新列表,但一旦遇到非橙色方块就立即停止。我们事先并不知道列表里有多少个橙色方块。

这就是while循环的典型应用。我们用代码来模拟这个过程:

squares = ['orange', 'orange', 'purple', 'blue']
new_squares = []
i = 0

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/2ce9083df959cdcda740730592b0f74a_10.png)

while i < len(squares) and squares[i] == 'orange':
    new_squares.append(squares[i])
    i = i + 1

代码解析:

  1. 我们创建空列表new_squares和索引i=0
  2. while语句会检查条件:i是否在列表长度内 当前元素是否为'orange'
  3. 只要条件为真,就执行缩进块内的代码:将当前元素添加到new_squares,并将索引i加1。
  4. 当遇到'purple'(第三个元素)时,条件squares[i] == 'orange'变为假,循环终止。


📝 总结

本节课中我们一起学习了Python中两种主要的循环结构:

  1. For循环:通常用于遍历序列(如列表、元组)或执行已知次数的迭代。我们学习了使用range函数控制迭代次数,以及使用enumerate函数同时获取元素索引和值。
  2. While循环:用于在指定条件保持为真时重复执行代码块。它适用于迭代次数未知,需要根据运行时条件决定是否继续的场景。

循环是编程中实现自动化和批量处理的基础工具。请务必通过实验课中的真实数据示例进行练习,以巩固对这些概念的理解。

009:函数定义

在本节课中,我们将学习Python中的函数。你将了解如何使用Python的一些内置函数,以及如何构建自己的函数。函数是代码复用的核心,理解它们对于高效编程至关重要。


🧩 什么是函数?

函数接收一些输入,然后产生输出或引发变化。它是一段可以重复使用的代码。你可以实现自己的函数,但在许多情况下,你会使用他人编写的函数。这时,你只需要知道函数如何工作,以及在某些情况下如何导入它们。

为了更直观地理解,我们可以将橙色和黄色的方块视为相似的代码块。通过输入运行这些代码,我们可以得到输出。如果我们定义一个函数来执行这个任务,我们只需要调用这个函数。让小的方块代表调用函数所需的代码行。

我们可以通过多次调用函数来替换这些冗长的代码行。现在,我们只需调用函数,代码变得更短,但执行的任务完全相同。


🔄 函数的工作流程

你可以将这个过程想象成这样:当我们调用函数 F1 时,我们将一个输入传递给函数。这些值被传递给你编写的所有代码行。函数返回一个值,你可以使用这个值。例如,你可以将这个值作为输入传递给一个新函数 F2。当我们调用这个新函数 F2 时,该值被传递给另一组代码行。函数返回一个值。这个过程不断重复,将值传递给你调用的函数。你可以保存这些函数并重复使用,或者使用他人的函数。


🛠️ Python的内置函数

Python有许多内置函数。你不需要知道这些函数内部如何工作,只需要知道它们执行什么任务。

以下是几个常用内置函数的示例:

  • len() 函数:接收一个序列类型(如字符串或列表)或集合类型(如字典或集合)的输入,并返回该序列或集合的长度。
    • 示例len([1, 2, 3, 4, 5, 6, 7, 8]) 返回 8
  • sum() 函数:接收一个可迭代对象(如元组或列表),并返回所有元素的总和。
    • 示例sum([10, 20, 30, 10]) 返回 70


📊 排序:函数 vs. 方法

有两种对列表进行排序的方式,它们的行为有所不同。

上一节我们介绍了内置函数,本节中我们来看看排序这个具体操作,它展示了函数和方法的一个关键区别。

以下是两种排序方式的对比:

  • 使用 sorted() 函数sorted() 函数返回一个新的已排序列表或元组,原始列表保持不变。
    • 示例
      album_ratings = [10.0, 8.5, 9.5]
      sorted_album_rating = sorted(album_ratings) # 返回新列表 [8.5, 9.5, 10.0]
      # album_ratings 仍然是 [10.0, 8.5, 9.5]
      
  • 使用 .sort() 方法.sort() 方法会直接修改原始列表,而不会创建新列表。
    • 示例
      album_ratings = [10.0, 8.5, 9.5]
      album_ratings.sort() # album_ratings 变为 [8.5, 9.5, 10.0]
      

我们可以用图表来帮助说明这个过程。使用 .sort() 方法时,代表列表 album_ratings 的矩形本身发生了变化。与之前使用 sorted() 函数的情况不同,列表 album_ratings 被改变了,并且没有创建新列表。


🏗️ 如何构建自定义函数

现在我们已经了解了如何使用Python中的函数,接下来看看如何构建我们自己的函数。

我们将从在Python中构建你自己的函数开始。这是一个Python函数的例子,它返回输入值加一的结果。

要定义一个函数,我们以关键字 def 开始。函数名应描述其功能。我们在括号内有函数的形式参数 a,后面跟着一个冒号。我们有一个带缩进的代码块。在这个例子中,我们将 a 加1并赋值给 b。然后我们返回或输出 b 的值。

定义函数后,我们可以调用它。函数将5加1并返回6。我们可以再次调用该函数,这次将其赋值给变量 cc 的值将是11。

让我们进一步探索。当你调用一个函数时,可以这样理解(请注意,这是Python的简化模型,Python底层并非完全如此工作):我们调用函数并给它输入5。可以认为值5被传递给了函数。现在,运行一系列命令。a 的值是5。b 将被赋值为6。然后我们返回 b 的值,即6。如果我们再次调用该函数,过程重新开始,我们传入8。执行后续操作。上次调用中发生的一切都会再次发生,只是 a 的值不同。函数返回一个值,这里是9。再次强调,这只是一个有帮助的类比。


📝 函数的更多特性

让我们尝试让这个函数更复杂一些。通常在前几行记录函数的功能,这告诉任何使用该函数的人它的作用。这个文档字符串用三引号包围。你可以使用 help 命令在函数上显示文档。

一个函数可以有多个参数。例如,函数 mult 将两个数字相乘,换句话说,它找到它们的乘积。如果我们传递整数2和3,结果是一个新的整数6。如果我们传递整数10和浮点数3.14,结果是一个浮点数31.4。

如果我们传入整数2和字符串“Michael Jackson”,字符串“Michael Jackson”会被重复两次。这是因为乘法符号也可以表示重复一个序列。如果你不小心用一个整数乘以一个字符串,而不是两个整数相乘,你不会得到错误。相反,你会得到一个字符串,你的程序可能会继续运行,但之后可能会失败,因为你在期望整数的地方得到了一个字符串。这个特性会使编码更简单,但你必须更彻底地测试你的代码。

在许多情况下,函数没有 return 语句。在这些情况下,Python将返回特殊的 None 对象。实际上,如果你的函数没有 return 语句,你可以将其视为函数根本不返回任何内容。例如,函数 MJ 只是打印名字“Michael Jackson”。我们调用该函数,它打印“Michael Jackson”。让我们定义一个不执行任何任务的函数 no_work。Python不允许函数有空的主体,所以我们可以使用关键字 pass,它不做任何事情,但满足非空主体的要求。如果我们调用该函数并打印它,函数返回 None。在后台,如果没有调用 return 语句,Python会自动返回 None

通常函数执行多个任务。这个函数打印一条语句,然后返回一个值。我们可以用这个表格来表示函数被调用时的不同值。我们以输入2调用函数。我们找到 b 的值。函数打印带有 ab 值的语句。最后,函数返回 b 的值,在这个例子中是3。

我们可以在函数中使用循环。这个函数打印出列表或元组的值和索引。我们以列表 album_ratings 作为输入调用该函数。让我们在右侧显示列表及其对应的索引。lst 用作函数 enumerate 的输入。这个操作会将索引传递给 i,将列表中的值传递给 rating。函数将开始遍历循环。函数将打印第一个索引和列表中的第一个值。我们继续遍历循环。irating 的值被更新。到达打印语句。类似地,打印列表和索引的下一个值。重复这个过程,直到打印出列表中的最终值。


🌐 变量的作用域

变量的作用域是程序中该变量可被访问的部分。在任何函数外部定义的变量被称为在全局作用域内,这意味着在它们被定义后,可以在任何地方访问。

这里我们有一个函数,它将字符串“DC”添加到参数 x 中。当我们到达 x 的值被设置为“AC”的部分时,这是在全局作用域内,意味着 x 在定义后可以在任何地方访问。在全局作用域内定义的变量称为全局变量。当我们调用函数时,我们进入一个新的作用域,即 add_dc 的作用域。我们传递一个参数给 add_dc 函数,在这个例子中是“AC”。在函数的作用域内,x 的值被设置为“ACDC”。函数返回值并被赋值给全局作用域内的 z。返回值后,函数的作用域被删除。

局部变量只存在于函数的作用域内。考虑函数 thriller。局部变量 date 被设置为1982。当我们调用该函数时,我们创建了一个新的作用域。在该函数的作用域内,date 的值被设置为1982。date 的值在全局作用域内不存在。

全局作用域内的变量可以与局部作用域内的变量同名而不会冲突。考虑函数 thriller。局部变量 date 被设置为1982。全局变量 date 被设置为2017。当我们调用该函数时,我们创建了一个新的作用域。在该作用域内,date 的值被设置为1982。如果我们调用该函数,它返回局部作用域内 date 的值,即1982。当我们在全局作用域内打印时,我们使用全局变量的值。变量的全局值是2017。因此,该值被设置为2017。

如果一个变量在函数内没有定义,Python将检查全局作用域。考虑函数 ACDC。该函数有一个变量 rating 没有赋值。如果我们在全局作用域内定义变量 rating,然后调用该函数,Python会看到变量 rating 没有值。因此,Python将离开该作用域,并检查变量 ratings 是否存在于全局作用域中。它将在 ACDC 的作用域内使用全局作用域中 ratings 的值。函数将打印出9。全局作用域中 z 的值将是10,因为我们加了一。rating 的值在全局作用域内将保持不变。

考虑函数 pink_floyd。如果我们用关键字 global 定义变量 claimed_sales,该变量将是一个全局变量。我们调用函数 pink_floyd。变量 claimed_sales 在全局作用域内被设置为字符串“45 million”。当我们打印该变量时,我们得到的值是“45 million”。

关于函数,你还可以做更多事情,请查看实验部分以获取更多示例。


📚 总结

在本节课中,我们一起学习了Python函数的核心概念。我们从了解函数的基本定义和工作流程开始,然后探索了Python的内置函数,如 len()sum()。我们区分了函数(如 sorted())和方法(如 .sort())在行为上的不同。接着,我们深入学习了如何定义自己的函数,包括参数传递、返回值、文档字符串以及函数内部的循环使用。最后,我们探讨了变量的作用域,理解了全局变量和局部变量的区别及其交互规则。掌握这些知识将使你能够编写更模块化、可重用和易于维护的代码。

010:异常处理 🛡️

在本节课中,我们将要学习Python中的异常处理。异常处理是编写健壮程序的关键技术,它允许程序在遇到错误时优雅地恢复,而不是直接崩溃。我们将解释异常处理的概念,演示其使用方法,并理解其基本原理。

什么是异常处理? 🤔

你是否曾经在应该输入文本的输入框中误输入了数字?大多数人都有过这样的经历,无论是出于错误还是测试程序。但你是否知道为什么程序会显示错误信息,而不是完成并终止程序?为了让错误信息出现,后台触发了一个事件。这个事件被激活是因为程序试图对输入的姓名进行计算,并发现输入包含数字而非字母。通过将这段代码包裹在异常处理器中,程序知道如何处理这类错误,并能输出错误信息以继续执行程序。这只是请求用户输入时可能发生的众多错误之一。

上一节我们介绍了异常处理的基本概念,本节中我们来看看异常处理是如何工作的。

Try-Except语句 🧪

我们将首先探索try-except语句。这种类型的语句会首先尝试执行try块中的代码。但如果发生错误,它会跳出并开始搜索匹配该错误的异常。一旦找到正确的异常来处理错误,它就会执行那行代码。

以下是try-except语句的基本结构:

try:
    # 尝试执行的代码
    result = 10 / 0
except ZeroDivisionError:
    # 处理特定异常
    print("不能除以零!")

处理特定异常 🎯

例如,假设你正在编写一个打开并写入文件的程序。程序启动后,由于数据无法读取而发生了错误。因为这个错误,程序跳过了try语句下的代码行,直接转到except行。由于这个错误属于IO错误的范畴,它向控制台打印了“无法打开或读取文件中的数据”。

编写简单程序时,有时我们只用一个except语句就能应付。但如果发生了未被IO错误捕获的另一个错误怎么办?如果发生这种情况,我们需要为这个except语句添加另一个。

以下是处理多个异常的例子:

try:
    file = open('myfile.txt', 'r')
    content = file.read()
    number = int(content)
except FileNotFoundError:
    print("文件未找到。")
except ValueError:
    print("文件内容无法转换为整数。")

避免捕获所有异常 ⚠️

对于这个except语句,你会注意到没有指定要捕获的错误类型。虽然这看起来是一个合理的步骤,让程序捕获所有错误而不终止,但这并不是最佳实践。

例如,也许我们的小程序只是一个超过一千行代码的大型程序的一部分。我们的任务是调试程序,因为它不断抛出错误,给用户造成干扰。在调查程序时,你发现这个错误不断出现。因为这个错误没有详细信息,你最终花费了数小时试图定位和修复错误。

使用Else和Finally语句 ✅

到目前为止,在我们的程序中,我们已经定义了如果发生错误应该打印出错误信息,但我们没有收到任何程序执行成功的通知。这就是我们可以添加else语句来给我们那个通知的地方。

通过添加这个else语句,它将向控制台提供一个通知,表明文件写入成功。

try:
    file = open('data.txt', 'w')
    file.write("Hello, World!")
except IOError:
    print("写入文件时发生错误。")
else:
    print("文件写入成功!")

现在我们已经定义了如果程序正确执行或发生错误时会发生什么,对于这个例子,还有最后一个语句要添加。

清理资源:Finally语句 🧹

我们正在打开一个文件,我们需要做的最后一件事是关闭文件。通过添加一个finally语句,它将告诉程序无论最终结果如何都要关闭文件,并向控制台打印“文件现已关闭”。

try:
    file = open('data.txt', 'w')
    file.write("Hello, World!")
except IOError:
    print("写入文件时发生错误。")
else:
    print("文件写入成功!")
finally:
    file.close()
    print("文件现已关闭。")

总结 📝

本节课中我们一起学习了如何编写try-except语句,为什么在创建异常时始终定义错误很重要,以及如何添加elsefinally语句。异常处理是确保程序稳定性和用户体验的重要组成部分。通过合理使用异常处理,我们可以使程序更加健壮和可靠。

011:对象与类 🧩

在本节课中,我们将学习Python中的对象。我们将探讨什么是对象,如何创建自定义的类,以及如何使用类的方法来操作对象的数据。理解这些概念是掌握Python面向对象编程的基础。


🧠 什么是对象?

Python中的每种数据类型(如整数、浮点数、字符串、列表、字典、布尔值)都是一个对象。每个对象都具备以下特征:

  • 类型:标识对象的种类。
  • 内部表示:对象内部存储数据的方式。
  • 方法:一组用于与对象数据交互的函数。

对象是特定类型的实例。例如,我们可以有多个整数对象,每个都是“整数”类型的实例。

对象实例示例

每次创建一个整数,我们就在创建“整数”类型的一个实例,或者说一个整数对象。

# 创建五个整数对象(实例)
num1 = 1
num2 = 2
num3 = 3
num4 = 4
num5 = 5

同样,每次创建一个列表,我们就在创建“列表”类型的一个实例,或者说一个列表对象。

# 创建五个列表对象(实例)
list1 = [1, 2]
list2 = [3, 4, 5]
list3 = ['a', 'b']
list4 = []
list5 = [6, 7, 8, 9]

我们可以使用 type() 命令来查看对象的类型。

print(type([1, 2, 3]))   # 输出:<class 'list'>
print(type(5))           # 输出:<class 'int'>
print(type("Hello"))     # 输出:<class 'str'>
print(type({'a': 1}))    # 输出:<class 'dict'>


🔧 类与方法

一个(或类型)的方法是该类每个实例都提供的函数。方法是我们与对象交互的方式。

我们一直在使用方法。例如,列表的 sort() 方法可以改变对象内部的数据。

我们通过在对象名称后加一个点 . 和方法名(后跟括号)来调用方法。

方法操作示例

考虑一个列表 ratingssort() 方法会改变对象内部的数据(即列表元素的顺序)。

ratings = [2, 5, 3, 1, 4]
ratings.sort()  # 调用 sort 方法
print(ratings)  # 输出:[1, 2, 3, 4, 5]

我们还可以调用 reverse() 方法再次改变列表。

ratings.reverse()  # 调用 reverse 方法
print(ratings)     # 输出:[5, 4, 3, 2, 1]

在许多情况下,你无需了解类及其方法的内部工作原理,只需知道如何使用它们即可。


🏗️ 创建自定义类

上一节我们了解了Python内置的类和方法。本节中,我们将学习如何创建自己的类。

在Python中,你可以创建自己的类型或类。一个类包含:

  • 数据属性:定义类的数据。
  • 方法:用于与数据交互的函数。

然后,我们可以创建该类的实例(即对象)。

定义类的数据属性

类的数据属性定义了该类。让我们创建两个类:Circle(圆形)和 Rectangle(矩形)。

  • 对于圆形:定义一个圆需要半径。我们还可以添加颜色属性,以便后续区分不同的实例。
    • 因此,Circle 类的数据属性是:radius(半径)和 color(颜色)。
  • 对于矩形:定义一个矩形需要高度和宽度。同样,我们添加颜色属性。
    • 因此,Rectangle 类的数据属性是:color(颜色)、height(高度)和 width(宽度)。

类的代码结构

要创建 Circle 类,需要包含类定义。class 关键字告诉Python你正在创建自己的类。

class Circle(object):
    # 类定义体
    pass

class Rectangle(object):
    # 类定义体
    pass
  • class 后跟类名(如 Circle)。
  • 括号中的 object 是该类的父类(在本课程中始终如此)。
  • pass 是一个占位符,表示暂时不写具体内容。

类只是一个蓝图。我们必须设置属性才能创建对象。


🎨 创建类的实例(对象)

我们可以创建 Circle 类型的对象实例。

# 创建 Circle 类的实例
circle1 = Circle(radius=4, color='red')
circle2 = Circle(radius=2, color='green')

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/bb4d1704e49a91687dc23a7d4e7854f0_58.png)

# 创建 Rectangle 类的实例
rect1 = Rectangle(height=2, width=2, color='blue')
rect2 = Rectangle(height=1, width=3, color='yellow')

现在,我们有了 Circle 类的不同对象,以及 Rectangle 类的不同对象。


⚙️ 深入类定义:构造函数与 self

让我们继续用Python构建 Circle 类。我们定义类,然后使用类构造函数 __init__ 来初始化每个实例的数据属性(radiuscolor)。

class Circle(object):
    def __init__(self, radius, color):
        self.radius = radius
        self.color = color

  • __init__ 函数是一个构造函数。它是一个特殊函数,告诉Python你正在创建一个新类。
  • self 参数指向新创建的类实例
  • radiuscolor 参数用于初始化类实例的 self.radiusself.color 数据属性。

我们可以类似地定义 Rectangle 类。

class Rectangle(object):
    def __init__(self, color, height, width):
        self.color = color
        self.height = height
        self.width = width

这次,类的数据属性是 colorheightwidth

理解对象创建过程

创建类之后,为了创建 Circle 类的对象,我们引入一个变量作为对象名称,并使用对象构造函数。

# 创建 Circle 对象
my_circle = Circle(10, 'red')

  • 对象构造函数由类名和参数(即数据属性)组成。
  • 当我们创建 Circle 对象时,我们像调用函数一样调用它。传递给 Circle 构造函数的参数用于初始化新创建的 Circle 实例的数据属性。

self 想象成一个包含对象所有数据属性的盒子会很有帮助。

访问与修改数据属性

输入对象名称,后跟一个点 . 和数据属性名称,可以获取数据属性的值。

print(my_circle.radius)  # 输出:10
print(my_circle.color)   # 输出:'red'

在Python中,我们也可以直接设置或更改数据属性。

my_circle.color = 'blue'  # 直接修改颜色属性
print(my_circle.color)    # 输出:'blue'

通常,为了改变对象中的数据,我们在类中定义方法


🛠️ 为类添加方法

我们已经看到数据属性如何构成定义对象的数据。方法是用于交互和更改数据属性的函数。

假设我们想改变一个圆的大小,这涉及到更改 radius 属性。我们给 Circle 类添加一个 add_radius 方法。

class Circle(object):
    def __init__(self, radius, color):
        self.radius = radius
        self.color = color

    def add_radius(self, r):
        self.radius = self.radius + r

  • 该方法是一个函数,需要 self 参数以及其他参数(这里是要添加的值 r)。
  • 在方法体内,我们将 r 加到数据属性 self.radius 上。

调用方法

我们创建一个对象并调用 add_radius 方法。

my_circle = Circle(2, 'red')  # 创建对象,radius=2, color='red'
print(my_circle.radius)       # 输出:2

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/bb4d1704e49a91687dc23a7d4e7854f0_108.png)

my_circle.add_radius(8)       # 调用方法,增加半径8
print(my_circle.radius)       # 输出:10

  • 我们通过添加点 . 后跟方法名和括号来调用方法。
  • 调用方法时,我们无需担心 self 参数,Python会为我们处理。
  • 在许多情况下,除了 self,方法定义中可能没有指定任何其他参数,因此调用函数时无需传递任何参数。

当调用 add_radius 方法时,它会通过更改 radius 数据属性的值来改变对象。


📝 实践与总结

在实验环节,我们还可以为类的构造函数参数添加默认值,并创建诸如 draw_circle 这样的方法(具体实现请参见实验)。

我们可以使用 dir() 函数来获取与类相关的数据属性和方法列表。将感兴趣的对象作为参数传递,返回值是该对象的属性和方法列表。

print(dir(my_circle))

输出中,被下划线包围的属性(如 __init__)是内部使用的,通常无需担心。常规外观的属性才是你需要关注的,它们是对象的方法和数据属性。

本节课总结
我们一起学习了Python中对象的核心概念。我们了解到对象是类的实例,拥有类型、内部数据和方法。我们学会了如何定义自己的类(如 CircleRectangle),包括使用 __init__ 构造函数初始化数据属性,以及如何为类添加方法来操作对象数据。最后,我们还了解了如何创建类的实例(对象),并访问或修改其属性。掌握这些是进行面向对象编程的重要基础。

012:Python文件读取操作教程

在本节课中,我们将学习如何使用Python内置的open函数创建文件对象,并从TXT文件中获取数据。我们将介绍文件对象的基本操作、读取方法以及最佳实践。

概述

我们将使用Python的open函数获取文件对象,并对该对象应用方法来读取文件数据。以下是打开文件example1.txt的基本步骤。

使用open函数

我们使用open函数。第一个参数是文件路径,由文件名和文件目录组成。

第二个参数是模式。常用值包括R用于读取、W用于写入和A用于追加。我们将使用R进行读取。最后,我们获得文件对象。

获取文件信息

现在我们可以使用文件对象获取文件信息。我们可以使用数据属性name获取文件名,结果是一个包含文件名的字符串。我们可以使用数据属性mode查看对象的模式,R表示读取。应始终使用方法close关闭文件对象。

有时这可能很繁琐,因此让我们使用with语句。使用with语句打开文件是更好的做法,因为它会自动关闭文件。

使用with语句

代码将运行缩进块中的所有内容,然后关闭文件。此代码读取文件example1.txt。我们可以使用文件对象file1。代码将执行缩进块中的所有操作,然后在缩进结束时关闭文件。

读取文件内容

方法read将文件的值作为字符串存储在变量file_stuff中。可以打印文件内容。可以检查文件是否关闭,但不能在缩进块外读取文件。不过,也可以在缩进块外打印文件内容。

我们可以打印文件内容。我们将看到以下内容。当我们检查原始字符串时,我们将看到\n。这是Python知道开始新行的方式。

使用readlines方法

我们可以使用方法readlines将每一行输出为列表中的一个元素。第一行对应列表中的第一个元素,第二行对应列表中的第二个元素,依此类推。

使用readline方法

我们可以使用方法readline读取文件的第一行。如果运行此命令,它将第一行存储在变量file_stuff中,然后打印第一行。

我们可以使用readline方法两次。第一次调用时,它将第一行保存在变量file_stuff中,然后打印第一行。

第二次调用时,它将第二行保存在变量file_stuff中,然后打印第二行。我们可以使用循环单独打印每一行,如下所示。

指定读取字符数

让我们将字符串中的每个字符表示为一个网格。我们可以指定要从字符串中读取的字符数,作为方法readlines的参数。

当我们在方法readlines中使用参数4时,我们打印出文件中的前四个字符。

逐步读取

每次调用该方法时,我们都会在文本中前进。如果我们使用参数16调用该方法,则打印前16个字符,然后换行。如果我们第二次调用该方法,则打印接下来的五个字符。最后,如果我们最后一次调用该方法,参数为9,则打印最后9个字符。查看实验以获取更多方法和其他文件类型的示例。😊

总结

在本节课中,我们一起学习了如何使用Python的open函数创建文件对象,以及如何通过readreadlinereadlines方法读取文件内容。我们还介绍了使用with语句自动管理文件关闭的最佳实践,并探讨了如何指定读取字符数以逐步处理文件数据。

013:Python文件写入操作

在本节课中,我们将学习如何使用Python的open()函数和文件对象来创建新文件、向文件中写入数据,以及如何复制文件内容。掌握文件写入操作是数据持久化存储的基础。

使用open()函数写入文件

我们可以使用open()函数来写入文件。通过该函数获取一个文件对象,然后使用write()方法将数据写入文件,最终文本会被保存到文件中。

以下是创建并写入文件的基本步骤:

  1. 使用open()函数,第一个参数是文件路径(包含文件名)。
  2. 如果指定目录下已存在同名文件,它将被覆盖。
  3. 将模式参数mode设置为‘w’,表示写入。
  4. 使用with语句,确保代码块执行完毕后文件会被正确关闭。

with open(‘example2.txt‘, ‘w‘) as file1:
    file1.write(“This is a test.\n”)

上面的代码会在当前目录下创建一个名为example2.txt的文件,并向其中写入一行文本“This is a test.”,\n表示换行。

连续写入与列表写入

如果我们连续多次调用write()方法,每次调用都会向文件中追加内容。

with open(‘example2.txt‘, ‘w‘) as file1:
    file1.write(“This is line A\n”)
    file1.write(“This is line B\n”)

这段代码会先写入“This is line A”,然后在新的一行写入“This is line B”。

我们也可以将一个列表中的每个元素写入文件。上一节我们介绍了基本的写入操作,本节中我们来看看如何批量写入数据。

以下是具体方法:

lines = [“Line 1\n”, “Line 2\n”, “Line 3\n”]
with open(‘example2.txt‘, ‘w‘) as file1:
    for line in lines:
        file1.write(line)

首先,我们使用with命令和open()函数创建一个文件。列表lines包含三个文本元素。然后,我们使用for循环读取列表lines的每个元素,并将其赋值给变量line

  • 循环的第一次迭代将列表的第一个元素写入文件。
  • 第二次迭代写入第二个元素,依此类推。
  • 循环结束时,文件会自动关闭。

追加模式与文件复制

除了覆盖写入(‘w‘),我们还可以将模式设置为追加(‘a‘)。这不会创建新文件,而是在现有文件末尾添加内容。

with open(‘example2.txt‘, ‘a‘) as file1:
    file1.write(“This is line C\n”)

这段代码会打开已存在的example2.txt文件,在文件末尾追加一行“This is line C”,然后关闭文件。

我们还可以将一个文件的内容复制到另一个新文件中。

  1. 首先,读取源文件example1.txt,通过文件对象read_file与其交互。
  2. 然后,创建一个新文件example3.txt,使用文件对象write_file与其交互。

with open(‘example1.txt‘, ‘r‘) as read_file:
    with open(‘example3.txt‘, ‘w‘) as write_file:
        for line in read_file:
            write_file.write(line)

for循环从文件对象read_file中逐行读取内容,并使用文件对象write_file将其存储到example3.txt文件中。

  • 第一次迭代复制第一行。
  • 第二次迭代复制第二行,直到读取到文件末尾。
  • 最后,两个文件都会被关闭。

总结

本节课中我们一起学习了Python的文件写入操作。我们掌握了如何使用open()函数在‘w‘(写入)和‘a‘(追加)模式下操作文件,如何使用write()方法写入字符串或列表内容,以及如何实现一个文件到另一个文件的复制。请查阅相关实验练习以获取更多示例。

014:Python应用于数据科学、AI与开发 - P14 📊 使用Pandas加载数据

在本节课中,我们将学习如何使用Python的Pandas库来加载和处理数据。Pandas是一个强大的数据分析工具,能够帮助我们高效地读取、操作和分析各种格式的数据文件。


什么是依赖库或库?📚

依赖库或库是预先编写好的代码,用于帮助解决特定问题。在本视频中,我们将介绍Pandas,这是一个用于数据分析的流行库。


导入Pandas库 🚀

我们可以使用以下命令导入Pandas库或依赖项。我们以import命令开始,后跟库的名称。

import pandas

现在,我们可以访问大量预构建的类和函数。这假设该库已安装在我们的实验环境中。所有必要的库都已安装。


加载CSV文件 📄

假设我们想使用Pandas的内置函数read_csv来加载一个CSV文件。CSV是一种用于存储数据的典型文件类型。我们只需输入单词pandas,然后是一个点号,以及带有所有输入参数的函数名称。

pandas.read_csv('file_path.csv')

频繁输入pandas可能会很繁琐。我们可以使用as语句来缩短库的名称。在这种情况下,我们使用标准缩写pd

import pandas as pd

现在,我们输入pd和一个点号,后跟我们想要使用的函数名称。在本例中,是read_csv

pd.read_csv('file_path.csv')

我们不仅限于缩写pd。例如,我们可以使用术语banana,但为了保持一致性,在本视频的其余部分我们将坚持使用pd


深入理解代码 🧐

Pandas允许您通过数据框(DataFrame)来处理数据。让我们详细了解一下从CSV文件到数据框的过程。

path = 'file_path.csv'
df = pd.read_csv(path)

变量path存储CSV文件的路径。它被用作read_csv函数的参数。结果存储在变量df中,这是数据框(DataFrame)的缩写。


查看数据框内容 👀

现在我们已经将数据加载到数据框中,可以开始处理它。我们可以使用head方法来检查数据框的前五行。

df.head()


加载Excel文件 📊

加载Excel文件的过程类似。我们使用Excel文件的路径和函数read_excel。结果也是一个数据框。

path = 'file_path.xlsx'
df = pd.read_excel(path)

从字典创建数据框 🗂️

数据框由行和列组成。我们可以从字典创建数据框。字典的键对应列标签,值是列表,对应行数据。

data = {
    'Column1': [1, 2, 3],
    'Column2': ['A', 'B', 'C']
}
df = pd.DataFrame(data)

然后,我们使用DataFrame函数将字典转换为数据框。我们可以直接看到表格与字典之间的对应关系:键对应表头,值是对应行的列表。


选择数据框的列 🔍

我们可以创建一个由单列组成的新数据框。只需输入数据框名称(在本例中为df)和用双括号括起来的列标题名称。

new_df = df[['Column1']]

结果是一个由原始列组成的新数据框。

您也可以对多列执行相同的操作。只需输入数据框名称(在本例中为df)和用双括号括起来的多个列标题名称。

new_df = df[['Column1', 'Column2']]

结果是一个由指定列组成的新数据框。


总结 📝

在本节课中,我们一起学习了如何使用Pandas库加载和处理数据。我们介绍了如何导入Pandas、加载CSV和Excel文件、从字典创建数据框,以及如何选择和查看数据框的特定列。掌握这些基本操作是进行数据分析和处理的重要第一步。

015:Pandas数据处理与保存

在本节课中,我们将学习如何使用Pandas库对DataFrame进行数据处理,包括查找唯一值、基于条件筛选数据,以及将处理后的数据保存为不同格式的文件。


🧮 查找唯一值

上一节我们介绍了DataFrame的基本结构,本节中我们来看看如何识别数据中的唯一值。

考虑一堆由13个不同颜色方块组成的积木。我们可以看到共有三种独特的颜色。

假设你想找出DataFrame某一列中有多少个唯一元素。当数据量从13个元素增加到数百万时,手动识别会变得非常困难。

Pandas提供了unique方法来确定DataFrame某一列中的唯一元素。

假设我们想确定数据集中专辑发行年份的唯一值。

我们输入DataFrame的名称,然后在方括号内输入列名released。接着我们应用unique方法。结果就是released列中的所有唯一元素。

以下是具体操作步骤:

  1. 使用df['column_name']语法选择目标列。
  2. 对该列应用.unique()方法。

unique_years = df['released'].unique()


🔍 基于条件筛选数据

了解了如何查找唯一值后,我们来看看如何根据特定条件筛选出我们感兴趣的数据行。

假设我们想创建一个仅包含1980年代歌曲的新数据库。我们可以先查看released列中发行年份晚于1979年的歌曲,然后选择对应的数据行。

我们可以在Pandas中用一行代码完成这个操作,但让我们先分解步骤。

我们可以对Pandas中的整个DataFrame使用不等式运算符。结果是一个布尔值序列。在我们的案例中,我们只需指定released列以及“晚于1979年”的不等式条件。结果是一个布尔值序列,当条件为真时结果为True,否则为False。

我们可以在一行代码中选择指定的列。我们只需使用DataFrame的名称,然后在方括号内放入前面提到的不等式条件,并将其赋值给变量DF1。现在我们就得到了一个新的DataFrame,其中每张专辑的发行年份都晚于1979年。

以下是实现筛选的步骤:

  1. 创建布尔条件序列。
  2. 使用该条件对DataFrame进行索引。

# 步骤分解
condition = df['released'] > 1979
DF1 = df[condition]

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/ee5d10cc85db3f503005f0c2c2121297_23.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/ee5d10cc85db3f503005f0c2c2121297_24.png)

# 或一行代码完成
DF1 = df[df['released'] > 1979]

💾 保存数据

筛选出所需数据后,最后一步是将结果保存下来,以便后续使用或分享。

我们可以使用to_csv方法保存新的DataFrame。参数是CSV文件的名称。请确保包含.csv扩展名。还有其他函数可以将DataFrame保存为其他格式。

以下是保存数据的基本语法:

DF1.to_csv('new_songs_after_1979.csv')

📝 课程总结

本节课中我们一起学习了Pandas数据处理与保存的核心操作。我们首先使用.unique()方法查找了数据列中的唯一值。接着,我们通过创建布尔条件并应用该条件进行索引,实现了基于特定条件(如年份)的数据筛选。最后,我们使用.to_csv()方法将处理后的DataFrame保存为CSV文件,以便持久化存储分析结果。这些技能是数据清洗和预处理的基础。

016:Python应用于数据科学、AI和开发 - P16 🧮 一维NumPy数组教程

在本节课中,我们将要学习NumPy库的基础知识,特别是关于一维数组(1D数组)的内容。NumPy是科学计算的核心库,为数据科学、人工智能和开发提供了强大的数组操作功能。

概述 📋

NumPy是一个用于科学计算的Python库。它提供了许多有用的函数。NumPy具有速度快、内存效率高等优点。NumPy也是Pandas库的基础。本视频将涵盖一维NumPy数组的基础知识、数组创建、索引与切片、基本操作以及通用函数。

创建NumPy数组 🛠️

上一节我们介绍了NumPy的概况,本节中我们来看看如何创建一个NumPy数组。

一个Python列表是一个容器,允许你存储和访问数据。每个元素都与一个索引相关联。我们可以使用方括号访问每个元素,如下所示。

一个NumPy数组(或ND数组)与列表类似。它的大小通常是固定的,并且每个元素都是相同类型(在本例中是整数)。我们可以通过首先导入NumPy,然后将列表转换为NumPy数组。

以下是创建和访问NumPy数组的步骤:

  1. 导入NumPy库:首先需要导入NumPy。
    import numpy as np
    
  2. 将列表转换为数组:使用np.array()函数。
    a = np.array([0, 1, 2, 3, 4])
    
  3. 访问数组元素:与列表类似,使用整数索引和方括号。
    a[0]  # 访问第一个元素
    

数组a的存储方式如下。如果我们检查数组的类型,会得到numpy.ndarray。由于NumPy数组包含相同类型的数据,我们可以使用属性dtype来获取数组元素的数据类型,在本例中是64位整数。

数组属性 📊

现在我们已经创建了数组,让我们来回顾一些基本的数组属性。

以下是使用数组a可以查看的一些关键属性:

  • size:数组中元素的数量。因为有五个元素,所以结果是5。
  • ndim:表示数组的维数或秩。在一维情况下,值为1。
  • shape:一个整数元组,表示数组在每个维度上的大小。对于一维数组,形状是(n,),其中n是元素个数。

我们也可以创建包含实数的NumPy数组。当我们检查数组类型时,得到的是numpy.ndarray。如果我们检查属性dtype,会看到float64,因为元素不是整数。NumPy还有许多其他属性,可以查阅NumPy官网了解更多。

索引与切片 🔪

了解了数组的基本属性后,本节我们来看看如何访问和修改数组中的元素。

我们可以更改数组的第一个元素为100。数组的第一个值现在是100。我们也可以更改数组的第五个元素。现在第五个元素是0。

与列表和元组类似,我们可以对NumPy数组进行切片。数组的元素对应以下索引。我们可以选择索引1到3的元素,并将其赋值给一个新的NumPy数组c。这些元素确实对应于索引。与列表一样,我们不计算与最后一个索引对应的元素。

我们可以为相应的索引分配新值。数组c现在有了新的值。有关NumPy用法的更多示例,请参阅实验或NumPy官网。

基本数组运算 ➕➖✖️

NumPy使得在数据科学中常见的许多操作变得更加容易。与常规Python相比,这些相同的操作在NumPy中通常计算速度更快,并且需要更少的内存。让我们回顾一下一维数组上的一些操作。

我们将在欧几里得向量的背景下查看许多操作,以使内容更有趣。

向量加法是数据科学中广泛使用的操作。考虑具有两个元素的向量u。类似地,考虑具有两个分量的向量v。在向量加法中,我们创建一个新向量zz的第一个分量是向量uv的第一个分量之和。同样,第二个分量是uv的第二个分量之和。这个新向量z现在是向量uv的线性组合。

使用NumPy,我们可以用一行代码执行向量加法。如果使用Python列表执行相同的任务,则需要多行代码,如屏幕右侧所示。此外,NumPy代码的运行速度也会快得多。如果你有大量数据,这一点很重要。

向量减法可以通过将加号改为减号来执行。如果对两个列表执行向量减法,则需要多行代码,如屏幕右侧所示。

向量与标量的乘法是另一个常见的操作。考虑向量y。我们只需将向量乘以一个标量值,在本例中是2。向量的每个分量都乘以2。在这种情况下,每个分量都加倍。

使用NumPy,向量与标量的乘法只需要一行代码。如果使用Python列表执行相同的任务,则需要多行代码,如屏幕右侧所示。此外,该操作也会慢得多。

哈达玛积(逐元素乘积) 是数据科学中另一个广泛使用的操作。考虑以下两个向量uvuv的哈达玛积是一个新向量zz的第一个分量是uv的第一个元素的乘积。类似地,第二个分量是uv的第二个元素的乘积。结果向量由uv的逐元素乘积组成。

我们也可以用一行NumPy代码执行哈达玛积。如果对两个列表执行哈达玛积,则需要多行代码,如屏幕右侧所示。

点积是数据科学中另一个广泛使用的操作。考虑向量uv。点积是由以下项给出的单个数字,表示两个向量的相似程度。我们将vu的第一个分量相乘。然后我们乘以第二个分量并将结果相加。结果是一个数字,表示两个向量的相似程度。

我们也可以使用NumPy的dot函数执行点积,并将其赋值给变量result

广播与通用函数 📡

考虑数组u。如果我们向数组添加一个标量值,NumPy会将该值添加到每个元素。这个特性被称为广播

一个通用函数是操作于ND数组上的函数。我们可以将通用函数应用于NumPy数组。考虑数组a,我们可以使用方法mean计算a中所有元素的平均值。这对应于所有元素的平均值。在本例中,结果是0。

还有许多其他函数。例如,考虑NumPy数组b,我们可以使用方法max找到最大值。我们看到最大值是5,因此方法max返回5。

使用NumPy进行函数映射与绘图 📈

我们可以使用NumPy创建将NumPy数组映射到新NumPy数组的函数。让我们在屏幕左侧实现一些代码,并使用屏幕右侧来演示发生了什么。

我们可以在NumPy中访问pi的值。我们可以在弧度中创建以下NumPy数组x。这个数组对应以下向量。我们可以将函数sine应用于数组x,并将值赋给数组y。这将对数组中的每个元素应用正弦函数。这对应于将正弦函数应用于向量的每个分量。结果是一个新数组y,其中每个值对应于对数组x中每个元素应用正弦函数的结果。

用于绘制数学函数的一个有用函数是linspacelinspace在指定间隔内返回均匀间隔的数字。我们指定序列的起点、序列的终点,参数num表示要生成的样本数,在本例中是5,样本之间的间隔是1。

如果我们将参数num改为9,我们会在从-2到2的区间内得到9个均匀间隔的数字。结果是后续样本之间的差值是0.5,而不是之前的1。

我们可以使用函数linspace从区间0到2π生成100个均匀间隔的样本。我们可以使用NumPy函数sin将数组x映射到新数组y。我们可以导入库pyplot作为plt来帮助我们绘制函数。由于我们使用的是Jupyter笔记本,我们使用命令%matplotlib inline来显示图表。

以下命令绘制一个图形。第一个输入对应于水平或X轴的值。第二个输入对应于垂直或Y轴的值。

总结 🎯

本节课中我们一起学习了一维NumPy数组的核心知识。我们涵盖了数组的创建、属性访问、索引切片、以及包括向量加法、减法、标量乘法、哈达玛积和点积在内的基本运算。我们还介绍了广播机制和通用函数,并学习了如何使用linspace和数学函数进行数组映射与简单绘图。NumPy的功能远不止于此,你可以通过实验或访问NumPy官网来探索更多高级特性。掌握NumPy是进行高效数据科学计算的重要基础。

017:二维NumPy数组

在本节课中,我们将学习如何创建和操作二维NumPy数组。二维数组是数据科学和机器学习中处理表格数据的基础。我们将涵盖数组的创建、索引、切片以及基本运算。


🏗️ 二维数组的创建与结构

我们可以创建多维的NumPy数组。本节将重点介绍二维数组,但NumPy也支持构建更高维度的数组。

考虑列表 A,它包含三个嵌套列表,每个列表大小相同。每个列表用不同颜色标记以便理解。我们可以将该列表转换为NumPy数组,如下所示:

import numpy as np
A = [[11, 12, 13], [21, 22, 23], [31, 32, 33]]
A = np.array(A)

将NumPy数组可视化为矩形数组很有帮助。每个嵌套列表对应矩阵的一行。


📐 数组的维度与形状

我们可以使用属性 ndim 来获取数组的轴数或维度数,这被称为秩。在NumPy中,秩指的是嵌套列表的层数,而非矩阵的线性独立列数。

第一个列表代表第一个维度(轴0),它包含的另一组列表代表第二个维度(轴1)。列表包含的列表数量与维度无关,而与列表的形状有关。

与一维数组类似,属性 shape 返回一个元组。使用矩形表示法有助于理解:元组的第一个元素对应原始列表中嵌套列表的数量(即行数),第二个元素对应每个嵌套列表的大小(即列数)。

例如,对于数组 A

  • A.ndim 返回 2
  • A.shape 返回 (3, 3)

我们还可以使用属性 size 获取数组的总元素数,即行数与列数的乘积。对于 AA.size 返回 9

建议在实验中尝试不同形状的数组并查看其他属性。


🔍 二维数组的索引与切片

我们可以使用方括号访问数组的不同元素。以下图像展示了列表式表示法与索引约定之间的关系。

第一个括号内的索引对应不同的嵌套列表(即不同的行),第二个括号内的索引对应嵌套列表内的特定元素(即列)。

使用矩形表示法时,第一个索引对应行索引,第二个索引对应列索引。

我们也可以使用单个括号来访问元素,但通常使用两个索引更清晰。

索引示例:

  • A[1, 2] 访问第二行、第三列的元素,值为 23
  • A[0, 0] 访问第一行、第一列的元素,值为 11

切片示例:

  • A[0, 0:2] 访问第一行的前两列。
  • A[0:2, 2] 访问前两行的最后一列。

➕ 二维数组的基本运算

数组加法

数组加法的过程与矩阵加法相同。考虑矩阵 XY,我们将相同位置的元素相加。结果是一个与 XY 大小相同的新矩阵,其中每个元素是 XY 对应元素的和。

在NumPy中,我们可以这样实现:

X = np.array([[1, 0], [0, 1]])
Y = np.array([[2, 1], [1, 2]])
Z = X + Y  # 结果:[[3, 1], [1, 3]]

标量乘法

将NumPy数组乘以标量与将矩阵乘以标量相同。考虑矩阵 Y,将其乘以标量 2,即矩阵中的每个元素都乘以 2

在NumPy中:

Y = np.array([[2, 1], [1, 2]])
Z = 2 * Y  # 结果:[[4, 2], [2, 4]]

逐元素乘法(哈达玛积)

两个数组的乘法对应于逐元素乘积或哈达玛积。考虑数组 XY,哈达玛积是将相同位置的元素相乘。

在NumPy中:

X = np.array([[1, 0], [0, 1]])
Y = np.array([[2, 1], [1, 2]])
Z = X * Y  # 结果:[[2, 0], [0, 2]]

矩阵乘法

我们也可以使用NumPy数组进行矩阵乘法。矩阵乘法稍微复杂一些,但以下是基本概述。

考虑矩阵 AB。在线性代数中,在将矩阵 A 乘以矩阵 B 之前,我们必须确保 A 的列数等于 B 的行数。

为了得到新矩阵的第 i 行第 j 列元素,我们取 A 的第 i 行与 B 的第 j 列的点积。

在NumPy中,我们可以使用 np.dot() 函数或 @ 运算符进行矩阵乘法:

A = np.array([[0, 1, 1], [1, 0, 1]])
B = np.array([[1, 1], [1, 1], [-1, 1]])
C = np.dot(A, B)  # 或 C = A @ B
# 结果:[[0, 2], [0, 2]]


📝 总结

本节课我们一起学习了二维NumPy数组的核心概念。我们了解了如何创建二维数组,如何获取其维度和形状信息。我们掌握了使用索引和切片来访问数组中的特定元素或子集。最后,我们学习了二维数组的基本运算,包括数组加法、标量乘法、逐元素乘法(哈达玛积)以及矩阵乘法。这些操作是进行数据分析和科学计算的基础。

NumPy的功能远不止于此,建议访问 numpy.org 探索更多内容。

018:简单API使用(上)🚀

在本节课中,我们将要学习应用程序接口,简称API。我们将讨论API是什么、API库、REST API(包括请求和响应),并通过一个使用PyCoinGecko库的加密货币数据获取示例来加深理解。

什么是API?🤔

API让两个软件组件能够相互通信。例如,你有一个程序、一些数据以及其他软件组件。你可以通过API,利用输入和输出来与其他软件进行通信。就像调用函数一样,你无需了解API内部如何工作,只需知道其输入和输出即可。

Pandas库实际上就是一组软件组件,其中许多甚至不是用Python编写的。当你有一些数据时,你可以使用Pandas API与其他软件组件通信来处理这些数据。

API库与实例

让我们通过一个更清晰的图示来理解。当你创建一个字典,然后使用DataFrame构造函数创建一个Pandas对象时,在API术语中,这被称为创建一个实例。字典中的数据被传递给Pandas API。然后,你可以使用这个DataFrame对象与API进行通信。

以下是具体过程:

  • 当你调用.head()方法时,DataFrame会与API通信,并显示数据的前几行。
  • 当你调用.mean()方法时,API会计算平均值并返回结果。

REST API简介 🌐

REST API是另一种流行的API类型。它允许你通过互联网进行通信,从而利用远程资源,如存储空间、更多数据、人工智能算法等。REST代表“表述性状态转移”。

在REST API中,你的程序被称为客户端。API通过互联网与你调用的Web服务进行通信。通信、输入(或称请求)和输出(或称响应)都遵循一套规则。

以下是REST API中的一些常见术语:

  • 客户端:指你或你的代码。
  • 资源:指Web服务。
  • 端点:客户端通过它来找到服务(我们将在下一节详细讨论)。
  • 请求:客户端发送给资源的信息。
  • 响应:资源返回给客户端的信息。

HTTP方法与通信过程

HTTP方法是在互联网上传输数据的一种方式。我们通过发送请求来告诉REST API要做什么。请求通常通过HTTP消息进行通信,该消息通常包含一个JSON文件,其中包含我们希望服务执行的操作指令。

这些指令通过互联网传输到Web服务,服务执行相应操作。类似地,Web服务通过HTTP消息返回响应,信息通常也以JSON文件的形式返回,并传输回客户端。

实战示例:使用PyCoinGecko API获取加密货币数据 💹

加密货币数据非常适合用于API实践,因为它不断更新,并且对加密货币交易至关重要。我们将使用PyCoinGecko这个Python客户端(或称包装器)来访问CoinGecko API,该API由CoinGecko每分钟更新一次。使用包装器是因为它更易于使用,让你能专注于数据收集任务。

我们还将介绍Pandas的时间序列函数,用于处理时间序列数据。

使用PyCoinGecko收集数据非常简单,只需三步:

  1. 安装并导入库。
  2. 创建一个客户端对象。
  3. 使用函数请求数据。

例如,以下代码获取比特币过去30天以美元计价的数据:

# 示例:获取比特币过去30天的数据
from pycoingecko import CoinGeckoAPI
cg = CoinGeckoAPI()
bitcoin_data = cg.get_coin_market_chart_by_id(id='bitcoin', vs_currency='usd', days=30)

在这种情况下,响应是一个JSON文件,在Python中表现为一个嵌套列表的字典,其中包含价格、市值和总交易量等数据,这些数据又包含Unix时间戳和对应时间点的价格。

我们只对价格数据感兴趣,因此使用键‘price’来选取它。为了简化操作,我们可以将这个嵌套列表转换为一个包含‘timestamp’‘price’两列的DataFrame。

‘timestamp’列的时间格式难以理解,我们将使用Pandas的to_datetime函数将其转换为更易读的格式。使用此函数,我们创建了可读的时间数据。输入是时间戳列,时间单位设置为毫秒。我们将输出附加到新的‘date’列。

现在,我们想创建一个K线图。为了获取每日K线所需的数据,我们将按日期分组,以找出每天的最低、最高、开盘(第一个)和收盘(最后一个)价格。最后,我们将使用Plotly库创建K线图并进行绘制。

现在,我们可以通过打开生成的HTML文件,并在浏览器标签页顶部点击“信任HTML”来查看K线图,它看起来应该类似这样。


本节课中,我们一起学习了API的基本概念,了解了API如何作为软件组件间的桥梁。我们重点介绍了REST API的工作原理,包括客户端、资源、请求和响应等核心概念。最后,我们通过一个获取和分析比特币价格数据的完整示例,实践了如何使用Python库调用外部API、处理JSON响应、转换时间格式以及进行基本的数据可视化。掌握API的使用是连接你的程序与广阔网络资源的关键技能。

019:简单API使用(下)—— 结合人工智能的API应用

在本节课中,我们将学习如何使用结合了人工智能技术的应用程序接口(API)。具体来说,我们将通过两个IBM Watson服务来实践:首先使用语音转文本API将音频文件转换为文字,然后使用语言翻译API将文字翻译成另一种语言。通过这个过程,你将理解如何通过API发送请求并处理返回的数据。

🤖 人工智能API概述

上一节我们介绍了API的基本概念,本节中我们来看看如何利用集成了人工智能的API完成实际任务。

我们将构建一个简单的流程:先对音频文件进行转录,再将得到的文本翻译成新的语言。在API调用中,你需要将音频文件发送给API,这种操作常被称为POST请求

随后,API会返回音频中人物所说的文字转录。在底层,API执行的是GET请求。接着,我们将这段希望翻译的文本发送给第二个API。

第二个API会将文本翻译并返回结果。在本例中,我们将实现从英语到西班牙语的翻译。接下来,我们先概述一下API密钥、端点以及我们将用到的Watson服务。

🔑 API密钥与端点

在开始实践之前,我们需要理解两个核心概念:API密钥端点。它们是访问任何API服务的基础。

API密钥是访问API的凭证。它是一串独特的字符,API通过它来识别和授权你的身份。通常,你的首次API调用就需要包含这个密钥。

对于许多API,每次调用都可能产生费用,因此,API密钥应像密码一样妥善保管,切勿泄露

端点则是服务所在的位置。它用于在互联网上定位API,就像一个网址。

理解了这些概念后,我们就可以开始动手操作了。

🎤 使用Watson语音转文本API

现在,我们将学习如何使用Watson语音转文本API来转录一个音频文件。

在开始实验前,你需要先注册并获取一个API密钥。我们会将一个音频文件下载到你的工作目录中。

以下是实现步骤:

首先,从IBM Watson库中导入必要的模块并设置服务。

from ibm_watson import SpeechToTextV1

# 设置服务端点(URL根据你的服务实例位置而定)
url_s2t = "YOUR_SPEECH_TO_TEXT_URL"

# 设置你的API密钥
apikey_s2t = "YOUR_SPEECH_TO_TEXT_APIKEY"

接着,创建一个语音转文本的适配器对象,用于与服务通信。

s2t = SpeechToTextV1(iam_apikey=apikey_s2t, url=url_s2t)

假设我们有一个名为my_audio.wav的音频文件。

# 以二进制读取模式打开音频文件
with open('my_audio.wav', 'rb') as audio_file:

然后,调用recognize方法将音频文件发送给Watson服务。

    response = s2t.recognize(audio=audio_file, content_type='audio/wav')

服务返回的响应是一个对象,其result属性是一个Python字典。

# 从响应结果中提取转录文本
recognized_text = response.result['results'][0]['alternatives'][0]['transcript']

此时,变量recognized_text中就包含了转录出的文本字符串。

🌐 使用Watson语言翻译API

上一节我们成功获取了文本,本节中我们来看看如何使用Watson语言翻译API将其翻译成其他语言。

首先,导入翻译模块并设置服务。

from ibm_watson import LanguageTranslatorV3

# 设置语言翻译服务的端点和API密钥
url_lt = "YOUR_LANGUAGE_TRANSLATOR_URL"
apikey_lt = "YOUR_LANGUAGE_TRANSLATOR_APIKEY"
version_lt = '2018-05-01'  # API版本日期,请参考文档

创建语言翻译器对象。

translator = LanguageTranslatorV3(iam_apikey=apikey_lt, url=url_lt, version=version_lt)

你可以获取服务支持的语言列表。

languages = translator.list_identifiable_languages().get_result()

例如,英语的代码是en,西班牙语是es

现在,使用之前转录的文本recognized_text进行翻译。

# 将英文翻译成西班牙文
translation_response = translator.translate(
    text=recognized_text,
    model_id='en-es'
).get_result()

响应结果是一个字典,其中包含翻译文本、字数等信息。

spanish_translation = translation_response['translations'][0]['translation']

变量spanish_translation现在包含了西班牙语的翻译文本。

你还可以进行反向翻译或翻译成其他语言。

# 将西班牙语翻译回英语
translation_back = translator.translate(
    text=spanish_translation,
    model_id='es-en'
).get_result()

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/298a7750b53a3d2577154a20054b7145_36.png)

# 将原始英文翻译成法语
french_translation = translator.translate(
    text=recognized_text,
    model_id='en-fr'
).get_result()

📝 课程总结

本节课中,我们一起学习了如何结合人工智能API来完成实际任务。我们首先了解了API密钥端点的重要性,然后逐步实践了使用IBM Watson语音转文本API将音频转换为文字,以及使用语言翻译API将文字翻译成不同语言(如西班牙语和法语)的完整流程。通过这个过程,你应该对如何通过代码调用复杂的云端AI服务有了初步的认识。

020:REST API与HTTP请求(上)🌐

在本节课中,我们将要学习HTTP协议的基础知识,包括统一资源定位符(URL)、HTTP请求与响应的结构,以及常见的HTTP方法和状态码。理解这些概念是使用REST API进行网络通信的关键。

概述:HTTP协议与网络通信

HTTP协议可以被视为通过网络传输信息的通用协议。它支持多种类型的REST API。回忆上一节内容,REST API的工作原理是发送请求,而该请求通过HTTP消息进行通信。HTTP消息通常包含一个JSON文件。

当您(客户端)访问一个网页时,您的浏览器会向托管该页面的服务器发送一个HTTP请求。服务器默认尝试查找索引文件(如index.html)来定位所需资源。如果请求成功,服务器将在HTTP响应中将对象发送给客户端,其中包含资源类型、长度等信息。

URL的组成部分

统一资源定位符(URL)是在网络上查找资源最常用的方式。我们可以将URL分解为三个部分。

以下是URL的三个核心组成部分:

  1. 协议: 这是通信协议。在本实验中,它始终是 http://
  2. 网络地址或基础URL: 用于定位资源的位置。例如 www.ibm.comwww.gitlab.com
  3. 路径: 资源在Web服务器上的具体位置。例如 /images/ibm-logo.png

HTTP请求与响应过程

让我们回顾一下请求和响应的过程。以下是一个使用GET请求方法的请求消息示例。HTTP还有其他方法可用。

在起始行中,我们有GET方法,这是一种HTTP方法。在这个例子中,它请求文件 index.html。请求头用于传递HTTP请求的附加信息。对于GET方法,请求头通常是空的。某些请求包含一个请求体,我们稍后会看到一个示例。

下表展示了响应消息的结构。响应起始行包含版本号,后跟一个描述性短语。在这个例子中,是 HTTP/1.0,状态码 200(表示成功),以及描述短语 OK。响应头包含额外信息。最后,响应体包含请求的文件,在这个例子中是一个HTML文档。

HTTP状态码

让我们看看其他的状态码。

以下表格展示了一些状态码示例。状态码的前缀表示其类别。

以下是常见的HTTP状态码类别和示例:

  • 1xx(信息响应): 例如 100,表示到目前为止一切正常。
  • 2xx(成功响应): 例如 200,表示请求已成功。
  • 4xx(客户端错误): 表示请求有问题。例如 401 表示请求未经授权。
  • 5xx(服务器错误): 例如 501 表示服务器不支持请求的功能。

HTTP方法

当发起一个HTTP请求时,会发送一个HTTP方法,它告诉服务器要执行什么操作。

以下是几种常见的HTTP方法:

  • GET: 从服务器检索数据。
  • POST: 向服务器发送数据。
  • PUT: 更新服务器上的数据。
  • DELETE: 删除服务器上的数据。

总结

本节课中,我们一起学习了HTTP协议的基础。我们了解了URL的结构、HTTP请求与响应的组成部分,以及状态码和HTTP方法的含义。在下一个视频中,我们将使用Python来实践GET方法(从服务器检索数据)和POST方法(向服务器发送数据)。

021:REST API与HTTP请求(下)🔗

在本节课中,我们将学习如何使用Python的Requests库处理HTTP协议。我们将重点介绍GET和POST请求,并通过实际示例展示如何发送请求、处理响应以及理解请求与响应的关键组成部分。

概述:Python Requests库 🌐

上一节我们介绍了REST API的基本概念。本节中,我们来看看如何使用Python的Requests库来实际执行HTTP请求。

Requests是Python中一个用于发送HTTP/1.1请求的流行库。它比Python内置的http.clienturllib等库更易于使用。

导入库与发送GET请求

首先,我们需要导入Requests库。以下代码展示了如何导入库并向IBM官网发送一个简单的GET请求。

import requests

r = requests.get('https://www.ibm.com')

变量r是一个响应对象,它包含了关于此次请求的所有信息,例如状态码。

检查响应状态与头部

我们可以通过响应对象的属性来检查请求的状态和详细信息。以下是检查状态码和响应头的方法。

# 打印状态码,200表示成功
print(r.status_code)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_16.png)

# 打印响应头部(返回一个字典)
print(r.headers)

# 获取特定的头部信息,例如日期
print(r.headers['date'])

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_18.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_19.png)

# 获取内容类型
print(r.headers['Content-Type'])

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_20.png)

# 检查响应编码
print(r.encoding)

查看响应内容

根据Content-Type,我们可以使用不同的属性来查看响应的主体内容。对于HTML内容,我们使用.text属性。

# 显示响应体中的HTML内容(前100个字符)
print(r.text[0:100])

使用GET请求查询参数

GET请求常用于从API检索数据,我们可以通过查询字符串(Query String)向服务器发送参数。在实验中,我们将使用httpbin.org这个服务进行演示。

查询字符串是URL的一部分,以问号?开始,后面跟着一系列参数=值对,各对之间用&符号连接。

以下是构建带参数的GET请求的步骤:

  1. 定义基础URL和端点(例如 /get)。
  2. 创建一个字典作为载荷(payload),其中键是参数名,值是参数值。
  3. 将这个字典传递给requests.get()函数的params参数。

# 定义基础URL
url_get = 'http://httpbin.org/get'

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_35.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_36.png)

# 创建查询参数字典
payload = {'name': 'Joseph', 'ID': '123'}

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_38.png)

# 发送带参数的GET请求
r = requests.get(url_get, params=payload)

发送请求后,我们可以检查URL、状态码和响应内容。

# 打印最终生成的URL,可以看到参数已被附加
print(r.url)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_42.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_43.png)

# GET请求没有请求体,所以此项为None
print(r.request.body)

# 打印状态码
print(r.status_code)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_45.png)

# 查看响应文本
print(r.text)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_46.png)

# 由于响应是JSON格式,我们可以将其解析为Python字典
print(r.json())
# 在返回的字典中,'args'键下包含了我们发送的查询参数

发送POST请求

与GET请求不同,POST请求将数据放在请求体中发送,而不是URL里。这更适合发送敏感或大量数据。

要发送POST请求,我们需要:

  1. 将端点改为 /post
  2. 使用requests.post()函数。
  3. 将包含数据的字典传递给data参数。
# 定义POST请求的URL
url_post = 'http://httpbin.org/post'

# 创建要发送的数据字典
payload_post = {'name': 'Joseph', 'ID': '123'}

# 发送POST请求
r_post = requests.post(url_post, data=payload_post)

比较GET与POST请求

我们可以通过对比来清晰地理解GET和POST请求的区别。

以下是GET与POST请求的关键区别:

  • URL:GET请求的参数显示在URL中;POST请求的URL是干净的,不包含参数。
  • 请求体:GET请求通常没有请求体(None);POST请求的数据包含在请求体中。
  • 响应内容:在httpbin.org的响应中,GET请求的参数在args键下,而POST请求发送的数据在form键下。

# 比较URL
print("GET URL:", r.url)      # 包含参数
print("POST URL:", r_post.url) # 不包含参数

# 比较请求体
print("GET 请求体:", r.request.body)   # 为 None
print("POST 请求体:", r_post.request.body) # 包含数据(字节形式)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/12e1d1f0a25977ea3013e2b2d8ba3645_63.png)

# 从POST响应中获取我们发送的数据
print(r_post.json()['form'])

总结 🎯

本节课我们一起学习了如何使用Python的Requests库进行HTTP通信。我们掌握了如何发送GET和POST请求,如何添加查询参数,以及如何查看和分析响应对象的状态码、头部和内容。理解GET与POST在数据传输方式(URL vs. 请求体)上的根本区别,是有效使用Web API的关键。

022:网页抓取HTML基础(选修)🔍

在本节课中,我们将回顾超文本标记语言(HTML),这是进行网页抓取的基础。网页上存在大量有用数据,例如房地产价格和编程问题的解决方案。万维网和维基百科是世界信息的宝库。如果你理解了HTML,就可以使用Python来提取这些信息。本视频将带你回顾一个基础网页的HTML结构、HTML标签的构成、HTML树状结构,并理解HTML表格。

🌐 网页与HTML概述

假设你有一个需求:从一个网页中找出国家篮球联盟球员的姓名和薪水。该网页由HTML构成,它包含一系列被尖括号包围的蓝色元素,这些元素称为标签。标签告诉浏览器如何显示内容,而我们需要的数据就在这些文本中。

🏷️ HTML标签的构成

让我们仔细看看一个HTML标签的构成。以下是一个HTML锚标签的例子:

<a href="https://www.ibm.com">IBM</a>

它将显示“IBM”,当你点击它时,会跳转到IBM.com的网站。

  • 标签名称:在这个例子中是 a。这个标签定义了一个超链接,用于从一个页面链接到另一个页面。将每个标签名称想象成Python中的一个类,而每个单独的标签则是该类的一个实例,会很有帮助。
  • 开始标签与结束标签:我们有开始标签 <a> 和结束标签 </a>。结束标签在标签名称前有一个斜杠 /。这些标签包含了内容,即网页上显示的部分。
  • 属性:属性由属性名和属性值组成。在这个例子中,href 是属性名,其值是目标网页的URL https://www.ibm.com

真实的网页更为复杂。根据你使用的浏览器,你可以选择HTML元素,然后点击“检查”。结果将允许你查看该页面的HTML。网页中还有其他类型的内容,如CSS和JavaScript,本课程将不涉及。

🌳 HTML树状结构

每个HTML文档实际上都可以被称为一个文档树。让我们看一个简单的例子。标签可以包含字符串和其他标签,这些元素就是该标签的子元素。我们可以将其表示为一个家族树,每个嵌套的标签都是树中的一个层级。

  • <html> 标签包含了 <head><body> 标签。
  • <head><body> 标签是 <html> 标签的后代。具体来说,它们是 <html> 标签的子元素。<html> 标签是它们的父元素。
  • <head><body> 标签是兄弟元素,因为它们处于同一层级。
  • <title> 标签是 <head> 标签的子元素,其父元素是 <head> 标签。<title> 标签是 <html> 标签的后代,但不是其子元素。
  • 标题标签(如 <h1>)和段落标签(<p>)是 <body> 标签的子元素,并且由于它们都是 <body> 标签的子元素,因此彼此是兄弟元素。
  • 加粗标签(<b>)是标题标签的子元素。

标签的内容也是树的一部分,但这会使图示变得复杂。

📊 HTML表格

接下来,让我们回顾HTML表格。要定义一个HTML表格,我们使用 <table> 标签。

以下是定义一个简单表格的代码结构:

<table>
  <tr>
    <th>表头1</th>
    <th>表头2</th>
  </tr>
  <tr>
    <td>行1, 单元格1</td>
    <td>行1, 单元格2</td>
  </tr>
  <tr>
    <td>行2, 单元格1</td>
    <td>行2, 单元格2</td>
  </tr>
</table>

  • 每个表格行由 <tr> 标签定义。
  • 第一行可以使用 <th> 标签作为表头。
  • 表格行中的单元格包含一组 <td> 标签,每个 <td> 定义一个表格单元格。

🎯 总结

本节课我们一起学习了HTML的基础知识,这是进行网页抓取的关键第一步。我们了解了网页如何由HTML构成,深入探讨了HTML标签的组成部分(包括标签名、属性和内容),认识了HTML文档的树状结构(父元素、子元素、兄弟元素),并学习了如何用HTML创建表格。掌握这些概念后,你将能够更好地理解网页的结构,为后续使用Python工具(如BeautifulSoup)从网页中提取所需数据打下坚实的基础。

023:网络数据抓取 🕸️

在本节课中,我们将要学习网络数据抓取。网络数据抓取是一个可以自动从网站提取信息的过程,它能在几分钟内完成原本需要数小时的手动工作。

什么是网络数据抓取? 🤔

如果你需要分析数百个数据点来找出体育队伍中的最佳球员,你会怎么做?你会开始从不同网站手动复制粘贴信息到电子表格吗?还是会花费数小时寻找正确数据,最终因为任务过于繁重而放弃?网络数据抓取正是在这些场景下能提供帮助的工具。

网络数据抓取是一个用于自动从网站提取信息的过程,可以轻松地在几分钟内完成,而不是数小时。

开始使用:Requests与Beautiful Soup 🚀

要开始网络数据抓取,我们只需要一点Python代码以及两个名为requestsbeautifulsoup4的模块的帮助。

假设你被要求从以下网页中找出国家篮球联赛球员的姓名和薪水。

首先,我们导入Beautiful Soup。我们可以将网页HTML作为字符串存储在变量html中。要解析文档,将其传递给Beautiful Soup构造函数。我们会得到一个Beautiful Soup对象soup,它将文档表示为嵌套的数据结构。

Beautiful Soup将HTML表示为一组树状对象,并提供了用于解析HTML的方法。

理解Beautiful Soup对象 🌳

使用我们创建的Beautiful Soup对象soup,标签对象对应于原始文档中的HTML标签。例如,title标签。

考虑<h3>标签。如果存在多个具有相同名称的标签,则选择具有该标签的第一个元素。在本例中,是“勒布朗·詹姆斯”。

我们看到姓名被包裹在粗体属性<b>中。要提取它,需要使用树状表示法。

变量tag_object位于此处。我们可以访问标签的子元素,或者沿着分支向下导航,如下所示:

tag_object.child

你可以通过使用parent属性在树中向上导航。变量tag_child位于此处,我们可以访问其父元素。这就是原始的tag_object

我们还可以找到tag_object的兄弟元素。我们只需使用next_sibling属性。

我们可以找到sibling1的兄弟元素。我们只需使用next_sibling属性。

考虑tag_child对象。你可以像字典中的键值对一样访问属性名称和值,如下所示:

tag_child.attrs

你可以将内容作为可导航字符串返回。这类似于支持Beautiful Soup功能的Python字符串。

探索find_all方法 🔍

现在,让我们回顾一下find_all方法。这是一个过滤器。

你可以使用过滤器基于标签名称、其属性、字符串文本或这些条件的某种组合进行过滤。

考虑披萨店的列表。像之前一样,创建一个Beautiful Soup对象,但这次将其命名为table

find_all方法会遍历标签的后代,并检索所有与你的过滤器匹配的后代。将其应用于标签为<tr>table。结果是一个Python可迭代对象,就像一个列表。

每个元素都是<tr>的标签对象。这对应于列表中的每一行,包括表头。

每个元素都是一个标签对象。因此,考虑第一行。例如,我们可以提取第一个表格单元格。

我们也可以遍历每个表格单元格。首先,我们通过变量row遍历列表tr_rows。每个元素对应于表格中的一行。

我们可以应用find_all方法来查找所有表格单元格。然后,我们可以为每一行遍历变量cells

在每次迭代中,变量cell对应于该特定行表格中的一个元素,我们继续遍历每个元素,并为每一行重复此过程。

将Beautiful Soup应用于网页 🌐

让我们看看如何将Beautiful Soup应用于网页以进行抓取。要抓取网页,我们还需要requests库。

第一步是导入所需的模块。使用requests库中的get方法来下载网页。输入是URL。

使用text属性获取文本,并将其分配给变量page,然后从变量page创建一个Beautiful Soup对象soup

这将允许你解析HTML页面,现在你可以开始抓取页面了。请查看实验部分以获取更多信息。

总结 📝

本节课中,我们一起学习了网络数据抓取的基础知识。我们定义了网络数据抓取,了解了Beautiful Soup对象的作用,学习了如何应用find_all方法,并掌握了抓取网站的基本步骤。通过结合使用requestsbeautifulsoup4库,你可以高效地从网页中提取所需的结构化数据。

024:多种文件格式处理(CSV/XML/JSON/XLSX)

在本节课中,我们将学习如何使用Python处理多种常见的数据文件格式,包括CSV、JSON、XML和XLSX。你将了解如何识别这些文件,以及使用哪些Python库来读取和提取其中的数据。


认识不同的文件格式

在收集数据时,你会发现需要处理多种不同的文件格式,才能完成数据驱动的分析或故事叙述。Python通过其预定义的库,可以使这个过程变得更简单。但在探索Python之前,让我们先了解一些常见的文件格式。

观察文件名时,你会注意到标题末尾有一个扩展名。这些扩展名让你知道文件的类型以及打开它需要什么。例如,如果你看到一个标题如 file_example.csv,你会知道这是一个CSV文件。但这只是不同文件类型的一个例子,还有更多类型,例如JSON或XML。


使用Python库读取数据

当遇到这些不同的文件格式并试图访问其中的数据时,我们需要利用Python库来简化这个过程。首先要熟悉的Python库是 pandas。通过在代码开头导入这个库,我们就能轻松读取不同类型的文件。

import pandas as pd

既然我们已经导入了pandas库,让我们用它来读取第一个CSV文件。在这个例子中,我们遇到了 file_example.csv 文件。第一步是将文件分配给一个变量,然后创建另一个变量,借助pandas库来读取文件。我们可以调用 read_csv 函数将数据输出到屏幕。

file_path = 'file_example.csv'
df = pd.read_csv(file_path)
print(df)

在这个例子中,数据没有表头,所以它将第一行数据作为了表头。由于我们不希望第一行数据作为表头,让我们看看如何纠正这个问题。


整理CSV数据输出

上一节我们学习了如何读取和输出CSV文件的数据,现在让我们让它看起来更有条理一些。

在上一个例子中,我们能够打印出数据,但因为文件没有表头,它将第一行数据打印成了表头。我们可以通过添加一个数据框属性来轻松解决这个问题。我们使用变量 df 来调用文件,然后添加 columns 属性。通过在我们的程序中添加这一行,我们可以将数据输出整齐地组织到每列指定的表头下。

df.columns = ['Column1', 'Column2', 'Column3']  # 根据实际列数命名
print(df)

处理JSON文件格式

接下来我们将探索的文件格式是JSON文件格式。在这种类型的文件中,文本是以一种独立于语言的数据格式编写的,类似于Python字典。读取此类文件的第一步是导入 json 库。

import json

导入json后,我们可以添加一行代码来打开文件,调用json的 load 属性开始读取文件,最后我们可以打印文件内容。

with open('file_example.json', 'r') as f:
    data = json.load(f)
print(data)


处理XML文件格式

下一个文件格式类型是XML,即可扩展标记语言。虽然pandas库没有直接读取此类文件的属性,但让我们探索如何解析这种类型的文件。

读取此类文件的第一步是导入 xml.etree.ElementTree 库。通过导入这个库,我们可以使用 ElementTree 属性来解析XML文件。然后我们添加列标题并将它们分配给数据框。

import xml.etree.ElementTree as ET
import pandas as pd

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/3694168a4f31e31a6990ca815878b938_43.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/3694168a4f31e31a6990ca815878b938_44.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/3694168a4f31e31a6990ca815878b938_45.png)

tree = ET.parse('file_example.xml')
root = tree.getroot()

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/3694168a4f31e31a6990ca815878b938_46.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/3694168a4f31e31a6990ca815878b938_47.png)

# 定义列标题
columns = ['Column1', 'Column2', 'Column3']
data = []

# 创建一个循环来遍历文档以收集必要的数据,并将数据附加到数据框中
for elem in root.findall('.//record'):  # 根据实际XML结构调整路径
    row = []
    for col in columns:
        # 假设每个记录下有对应标签
        cell = elem.find(col).text if elem.find(col) is not None else ''
        row.append(cell)
    data.append(row)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/3694168a4f31e31a6990ca815878b938_49.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/ibm-dtsci-4/img/3694168a4f31e31a6990ca815878b938_50.png)

df = pd.DataFrame(data, columns=columns)
print(df)


课程总结

本节课中,我们一起学习了如何识别不同的文件类型,如何使用Python库来提取数据,以及在收集数据时如何使用数据框。我们掌握了处理CSV、JSON和XML文件的基本方法,这是进行数据科学分析的重要基础技能。

posted @ 2026-03-26 08:53  布客飞龙II  阅读(4)  评论(0)    收藏  举报