1. NumPy介绍
这张图片介绍了Python中两个非常重要的科学计算库:NumPy和SciPy,以及它们的核心功能和特性。
NumPy
NumPy(Numerical Python)是一个开源的Python科学计算库,用于进行大规模数值和矩阵运算。以下是图片中提到的NumPy的关键特性:
- NumPy数组:类似于Matlab中的矩阵,NumPy数组是NumPy的核心数据结构,用于存储同类型数据的集合。
- 数据分析的核心基础库:NumPy提供了大量的数学函数来操作数组,使其成为数据分析和科学计算的基础。
- 数组的生成和方法:NumPy提供了多种方法来生成数组,并提供了丰富的方法来操作这些数组。
- 数组广播 :NumPy支持数组广播,这是一种强大的机制,允许NumPy用不同大小的数组进行算术运算。广播规则允许较小的数组"扩展"以匹配较大数组的形状,只要它们在相应的维度上兼容。例如,一个形状为
2x3x1
的数组可以与一个形状为5x1x3x4
的数组进行运算,因为其中一个维度为1,可以广播以匹配另一个数组的相应维度。 - 高维数组的索引(花式索引):NumPy允许使用复杂的索引技术,如花式索引,来选择数组的子集。
- 随机数组的生成:NumPy提供了生成随机数数组的功能,这对于模拟和统计分析非常有用。
SciPy
SciPy(Scientific Python)是一个开源的Python算法库和数学工具包,用于科学和工程计算。它建立在NumPy之上,提供了更多的功能。以下是图片中提到的SciPy的关键模块:
- 插值 :
scipy.interpolate
模块提供了各种插值方法,用于估计数据点之间的值。 - 统计 :
scipy.stats
模块提供了统计分布、统计测试和统计数据的统计描述。 - 优化 :
scipy.optimize
模块提供了多种优化算法,用于找到函数的最小值或最大值。 - 积分 :
scipy.integrate
模块提供了数值积分的方法,用于计算定积分或不定积分。 - 线代 :
scipy.linalg
模块提供了线性代数的基本操作,包括矩阵分解、特征值问题等。
这两个库是Python科学计算生态系统的基石,广泛应用于数据科学、机器学习、工程和科学领域。
2. 列表和数组的区别
数组(Arrays)和列表(Lists)是编程中用于存储多个值的两种不同的数据结构,它们在不同编程语言中有着不同的实现和特性。在Python中,列表是一种内置的数据结构,而数组则通常通过第三方库(如NumPy)实现。以下是数组和列表在Python中的主要区别:
1. 元素类型
- 列表:可以包含不同类型的元素,例如整数、字符串、浮点数、甚至是其他列表或对象。列表是异构的。
- NumPy数组:通常要求所有元素都是相同的数据类型,这使得数组在处理数值计算时更加高效。数组是同构的。
2. 性能
- 列表:由于其灵活性,列表在执行数值计算时可能不如数组高效,尤其是在处理大量数据时。
- NumPy数组:为了提高性能,NumPy数组在内存中是连续存储的,这使得它们在进行向量化操作时非常快速。
3. 内存使用
- 列表:由于存储了元素的类型信息,列表可能使用更多的内存。
- NumPy数组:因为所有元素类型相同,数组可以更紧凑地存储数据,通常使用更少的内存。
4. 功能和方法
- 列表 :Python的列表提供了丰富的方法,如
append()
,extend()
,insert()
,remove()
,pop()
等,用于添加、删除和修改元素。 - NumPy数组 :NumPy数组提供了大量的数学和统计方法,这些方法在列表中不可用,如
mean()
,std()
,sum()
,cumprod()
等。
5. 索引和切片
- 列表:支持基于0的索引和负索引,以及切片操作。
- NumPy数组:同样支持基于0的索引、负索引和切片,但还支持更高级的索引技术,如花式索引和布尔索引。
6. 广播
- 列表:不支持广播机制。
- NumPy数组:支持广播,这是一种强大的机制,允许NumPy用不同大小的数组进行算术运算。
7. 可变性
- 列表:是可变的,意味着你可以在不改变列表身份的情况下更改其内容。
- NumPy数组:也是可变的,但对数组的某些操作(如改变形状或大小)会创建一个新的数组。
8. 使用场景
- 列表:适用于存储不同类型的数据,或者当你需要存储的数据结构不规则时。
- NumPy数组:适用于数值计算,特别是当你需要处理大量数值数据并进行向量化操作时。
在Python中,如果你需要进行高效的数值计算,使用NumPy数组通常是更好的选择。如果你需要一个灵活的数据结构来存储不同类型的数据,那么列表可能更合适。
对两者进行形象化的解释
让我们通过一些比喻来形象化地解释Python中数组和列表的区别:
列表(Lists):购物清单
想象一下,你有一个购物清单,上面可以写任何你想要的东西,无论是苹果、牛奶还是洗洁精。你可以在清单上添加新项目,划掉已经购买的物品,或者在任何位置插入新项目。这个清单没有严格的规则,你可以随意修改它。
- 灵活性:就像购物清单可以包含任何商品,Python列表可以包含任何类型的元素。
- 修改:你可以在购物清单上自由添加或删除项目,同样,Python列表也允许你添加、删除或修改元素。
数组(Arrays):图书馆的书架
现在,想象一下图书馆里的书架。每个书架(数组)都是为特定类型的书设计的,比如小说、科学或历史。你不能在小说书架上放一本科学书。书架上的书籍按照一定的顺序排列,你可以通过编号快速找到它们。
- 统一性:图书馆的每个书架都只存放一种类型的书,同样,NumPy数组中的所有元素必须是相同的数据类型。
- 效率:图书馆的书籍按照编号排列,使得查找变得非常快速。NumPy数组在内存中连续存储,这使得它们在进行数值计算时非常高效。
性能:赛车与普通汽车
- 列表:就像一辆普通汽车,它可以在各种道路上行驶,但可能不是最快的。在处理大量数据或需要高性能计算时,列表可能不是最高效的选择。
- NumPy数组:就像一辆赛车,它在直道上(数值计算)可以跑得非常快,但在曲折的山路上(复杂的数据结构)可能不太灵活。
内存使用:小房子与大房子
- 列表:就像一个小房子,每个房间(元素)都可以存放不同的东西,但可能需要更多的空间来存放各种物品。
- NumPy数组:就像一个大房子,所有房间(元素)都是相同的,这使得空间利用更加高效,但可能不允许存放不同类型的物品。
通过这些比喻,我们可以更直观地理解Python中列表和数组的区别,以及它们在不同场景下的适用性。列表提供了灵活性和多样性,而数组提供了效率和统一性。
3. Python中的数据类型
在Python中,数组通常是指NumPy库中的数组,它们支持多种数据类型。NumPy数组的数据类型(dtype)决定了数组中每个元素的存储方式和所占空间。以下是一些常见的NumPy数据类型:
-
整数类型:
int8
:8位有符号整数int16
:16位有符号整数int32
:32位有符号整数int64
:64位有符号整数uint8
:8位无符号整数uint16
:16位无符号整数uint32
:32位无符号整数uint64
:64位无符号整数
-
浮点类型:
float16
:16位半精度浮点数float32
:32位单精度浮点数float64
:64位双精度浮点数float128
:128位扩展精度浮点数(在某些平台上可用)
-
复数类型:
complex64
:64位复数(32位实部和32位虚部)complex128
:128位复数(64位实部和64位虚部)complex256
:256位复数(在某些平台上可用)
-
布尔类型:
bool_
:布尔类型,用于存储True或False值
-
对象类型:
object_
:可以存储Python对象的数组
-
字符串类型:
str_
:字符串类型,用于存储文本数据bytes_
:字节类型,用于存储原始字节数据unicode_
:Unicode字符串类型,用于存储Unicode文本数据
-
日期和时间类型:
datetime64
:日期和时间类型,可以指定不同的时间分辨率,如datetime64[s]
表示秒级分辨率
-
时间差类型:
timedelta64
:时间差类型,用于表示两个日期或时间之间的差异
-
自定义类型:
- 用户可以定义自己的数据类型,通过组合现有的数据类型来创建结构化数组。
NumPy数组的dtype是固定的,这意味着一旦数组被创建,其dtype就不能改变。如果你需要改变数组的数据类型,你必须创建一个新的数组。例如:
python
import numpy as np
# 创建一个整数数组
int_array = np.array([1, 2, 3], dtype=np.int32)
# 创建一个浮点数数组
float_array = np.array([1.0, 2.0, 3.0], dtype=np.float64)
# 创建一个布尔数组
bool_array = np.array([True, False, True], dtype=np.bool_)
# 创建一个字符串数组
str_array = np.array(['hello', 'world'], dtype=np.str_)
在创建数组时,你可以指定dtype参数来定义数组的数据类型。如果不指定,NumPy会根据提供的元素自动推断dtype。
4. 数组中axis是什么
在NumPy和类似库中,axis
是一个非常重要的概念,它用于指定在多维数组(如矩阵)上进行操作的维度。axis
参数在许多NumPy函数中都有出现,比如mean()
, std()
, sum()
, argmax()
等,它允许你指定沿着哪个轴进行计算。
理解axis
在二维数组(矩阵)中,axis
可以取以下几个值:
axis=0
:沿着列操作,即对每一列的元素进行操作。这通常意味着函数将应用于数组的每一行。axis=1
:沿着行操作,即对每一行的元素进行操作。这通常意味着函数将应用于数组的每一列。
在更高维度的数组中,axis
可以是任何从0到n-1
的整数(其中n
是数组的维度数),表示沿着第axis
个维度进行操作。
示例
假设你有一个二维数组,表示为一个矩阵:
python
import numpy as np
# 创建一个3x3的数组
array_2d = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
如果你想计算每一列的平均值,你可以这样做:
python
mean_by_column = np.mean(array_2d, axis=0)
这将返回一个包含每列平均值的一维数组:[4., 5., 6.]
。
相反,如果你想计算每一行的平均值,你可以这样做:
python
mean_by_row = np.mean(array_2d, axis=1)
这将返回一个包含每行平均值的一维数组:[2., 5., 8.]
。
多维数组
对于多维数组,axis
的概念扩展到更多的维度。例如,一个三维数组可以看作是一个"堆叠"的矩阵,你可以沿着第一个维度(axis=0
)、第二个维度(axis=1
)或第三个维度(axis=2
)进行操作。
注意事项
- 如果不指定
axis
,某些函数可能会返回一个降维的结果,或者在所有元素上进行操作。 - 在使用
axis
时,确保它不超过数组的维度数减一(例如,对于三维数组,axis
的有效值是0、1或2)。
通过理解axis
,你可以更精确地控制NumPy函数在多维数组上的操作维度,这对于数据分析和科学计算至关重要。
5. 如何用numpy实现矩阵
直接写就可以
在Python中,使用NumPy库可以方便地实现矩阵的各种操作。以下是一些基本的步骤和示例,展示如何使用NumPy来创建和操作矩阵:
1. 安装NumPy
如果你还没有安装NumPy,可以通过pip安装:
bash
pip install numpy
2. 导入NumPy
在Python脚本或交互式环境中导入NumPy:
python
import numpy as np
3. 创建矩阵
有多种方式可以创建NumPy矩阵:
从列表创建矩阵
python
# 使用嵌套列表创建矩阵
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(matrix)
使用np.zeros
创建零矩阵
python
# 创建一个3x3的零矩阵
zero_matrix = np.zeros((3, 3))
print(zero_matrix)
使用np.ones
创建单位矩阵
python
# 创建一个3x3的单位矩阵
ones_matrix = np.ones((3, 3))
print(ones_matrix)
使用np.eye
创建对角矩阵
python
# 创建一个3x3的对角矩阵
identity_matrix = np.eye(3)
print(identity_matrix)
使用np.random
创建随机矩阵
python
# 创建一个3x3的随机矩阵
random_matrix = np.random.rand(3, 3)
print(random_matrix)
4. 矩阵的基本操作
矩阵加法
python
# 矩阵加法
matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6], [7, 8]])
sum_matrix = matrix1 + matrix2
print(sum_matrix)
矩阵乘法
python
# 矩阵乘法
product_matrix = np.dot(matrix1, matrix2)
print(product_matrix)
矩阵转置
python
# 矩阵转置
transpose_matrix = matrix1.T
print(transpose_matrix)
矩阵的逆
python
# 矩阵的逆(需要是方阵)
if matrix1.shape[0] == matrix1.shape[1]:
inverse_matrix = np.linalg.inv(matrix1)
print(inverse_matrix)
矩阵的行列式
python
# 矩阵的行列式(需要是方阵)
if matrix1.shape[0] == matrix1.shape[1]:
det = np.linalg.det(matrix1)
print(det)
5. 高级操作
NumPy提供了许多用于矩阵运算的高级函数,如特征值、奇异值分解等,这些都可以在numpy.linalg
模块中找到。
通过这些基本步骤,你可以开始使用NumPy进行矩阵运算和更复杂的数值计算。NumPy的文档提供了更详细的信息和高级功能。
矩阵乘法的实现
执行矩阵乘法
在NumPy中,可以使用dot()函数或者@运算符来执行矩阵乘法:
使用dot()函数
使用dot函数进行矩阵乘法
product = np.dot(matrix_a, matrix_b)
print("Matrix product using dot():\n", product)
使用@运算符
使用@运算符进行矩阵乘法
product = matrix_a @ matrix_b
print("Matrix product using @ operator:\n", product)
6. 广播机制
NumPy数组的广播(Broadcasting)机制是一种强大的特性,它允许NumPy在执行数组运算时,自动扩展较小的数组以匹配较大数组的形状。这种机制在不实际复制数据的情况下,提供了一种便捷的方式来执行数组间的算术运算。广播机制遵循以下规则:
-
维度匹配:从两个数组的尾部(最右边)开始比较维度,如果两个数组在某个维度上的长度相同,或者其中一个数组在该维度上的长度为1,则认为这两个维度是兼容的。
-
广播扩展:如果一个数组在某个维度上的长度为1,NumPy会将其沿着该维度扩展以匹配另一个数组的形状。这意味着长度为1的维度可以被视为任何长度。
-
逐元素运算:一旦两个数组的形状兼容,NumPy就会逐元素地执行运算。在扩展后的数组中,每个元素都会与另一个数组中相应位置的元素进行运算。
广播示例
假设有两个数组 a
和 b
:
python
import numpy as np
a = np.array([1, 2, 3]) # 形状为 (3,)
b = np.array([[1], [2], [3]]) # 形状为 (3, 1)
尽管 a
和 b
的形状不同,但它们在进行逐元素加法时可以广播:
python
c = a + b # 结果的形状为 (3, 3)
在执行加法时,a
会在列方向上广播,b
会在行方向上广播,以匹配对方的形状。结果是:
[[2 2 3]
[3 4 5]
[4 5 6]]
广播的维度规则
- 如果两个数组的维度不同,那么较小维度的数组会在前面补1,直到两个数组的维度相同。
- 如果两个数组在某个维度上的长度相同,或者其中一个数组在该维度上的长度为1,那么这两个数组在该维度上是兼容的。
- 如果两个数组在某个维度上的长度都不为1,且不相等,那么它们在该维度上不兼容,不能进行广播。
广播的用途
广播机制在NumPy中非常有用,因为它允许你:
- 进行不同大小数组间的运算,而不需要显式地重塑数组。
- 简化代码,减少内存使用,因为不需要复制数据来扩展数组。
- 轻松实现向量化操作,如将一个值加到数组的每个元素上,或者比较数组与标量的每个元素。
广播是NumPy中实现高效数值计算的关键特性之一。