1.Numpy简介,ndarray介绍以及效率问题
- 定义:NumPy(Numerical Python)是一个开源的 Python 科学计算库,主要用于快速处理任意维度的数组。
- 优势:支持常见的数组和矩阵操作,相比直接使用 Python 进行数值计算,代码更加简洁。
- 核心对象:使用
ndarray
对象来处理多维数组,该对象是一个快速且灵活的大数据容器,能够高效地存储和处理大量数据。 - 简而言之,ndarray就是一个对象,来处理多维数组
import numpy as np# 创建ndarray
score = np.array([[80, 89, 86, 67, 79],[78, 97, 89, 67, 81],[90, 94, 78, 67, 74],[91, 91, 90, 67, 69],[76, 87, 75, 67, 86],[70, 79, 84, 67, 84],[94, 92, 93, 67, 64],[86, 85, 83, 67, 80]])
np.array()
是 NumPy 库中的一个函数,用于创建ndarray
对象。- 函数的参数是一个嵌套的列表,外层列表的每个元素(即每个子列表)代表一名学生的各科成绩,从左到右依次对应语文、数学、英语、政治、体育成绩。
- 执行这行代码后,会将这个嵌套列表转换为一个二维的
ndarray
对象,并赋值给变量score
。此时,score
就可以用来进行各种基于数组的操作,比如计算每门课的平均分、找出每个学生的最高分等。
ndarray
对象特点体现
- 同质性:
ndarray
中的所有元素必须是相同类型。在这个成绩示例中,所有成绩都是整数类型。如果尝试混合不同类型的数据(比如将某个成绩写成字符串),NumPy 会自动进行类型转换(可能导致数据丢失或错误)。 - 多维性:这里创建的是二维
ndarray
,可以方便地表示表格型数据。同时,ndarray
可以是任意维度,比如一维ndarray
可以表示一组同类型的数值,三维ndarray
可以用于表示图像数据(长、宽、通道维度)等。 - 高效性:
ndarray
在存储和处理大量同类型数据时,相比 Python 原生的列表更加高效,能够大大提升计算速度,这也是 NumPy 在科学计算中广泛应用的重要原因之一。
高效原因:
- 内存块风格:
ndarray
存储数据时,数据与数据的地址连续。因为其所有元素类型相同,内存可连续分配。而 Python 原生列表元素类型任意,只能通过寻址找下一个元素。这使得ndarray
在批量操作数组元素时速度更快。虽然在通用性上不如 Python 原生列表,但在科学计算中,ndarray
能减少循环语句,代码更简洁。 - 支持并行化运算(向量化运算):NumPy 内置并行运算功能,当系统有多个核心时 ,进行某种计算时,NumPy 会自动并行计算,提高运算效率。
- 效率远高于纯 Python 代码:NumPy 底层用 C 语言编写,内部解除了全局解释器锁(GIL),对数组的操作速度不受 Python 解释器限制,相比纯 Python 代码,执行效率更高
2.N维数组对象ndarray
2.1ndarray的属性(即对象的属性,类里边定义好的属性,用的时候就是已创建对象.属性,不加括号)
常用对象.shape和对象.dtype
2.2数组的形状
可以有n维
2.3数组类型(使用dtype可得类型)
ndarray对象必须类型相同
np.string_ 字符串类型
常用的就是np.int64/32 np.float64/32 np.string_ np.objext_
2.4基本操作
2.4.1数组生成
2.4.1.1 0-1数组
生成数组的函数介绍
np.ones(shape, dtype)
:用于创建一个指定形状(shape
)和数据类型(dtype
)的数组,数组元素全部初始化为 1。shape
是一个整数或整数元组,表示数组的维度大小;dtype
可选,指定数组元素的数据类型,默认是float64
。np.ones_like(a, dtype)
:以给定数组a
为模板,创建一个形状和a
相同的数组,元素全部初始化为 1。同样,dtype
可选,用于指定新数组的元素类型,若不指定,则沿用a
的元素类型。np.zeros(shape, dtype)
:创建一个指定形状(shape
)和数据类型(dtype
)的数组,元素全部初始化为 0。参数含义与np.ones
类似。np.zeros_like(a, dtype)
:根据给定数组a
的形状,创建一个元素全部为 0 的数组。dtype
可选,可改变新数组的元素类型。
代码示例
ones = np.ones([4,8])
- 这行代码使用
np.ones
函数创建一个二维数组ones
。参数[4, 8]
表示数组的形状,即 4 行 8 列。由于没有指定dtype
,按照默认规则,数组元素的数据类型为float64
。 - 从返回结果可以看到,数组中每个元素的值都是 1.0 ,符合
np.ones
函数的功能。
- 这行代码使用
np.zeros_like(ones)
- 这行代码以数组
ones
为模板,使用np.zeros_like
函数创建一个新的数组。新数组的形状和ones
相同,都是 4 行 8 列。并且因为没有指定dtype
,新数组的数据类型也和ones
一样,为float64
。 - 从返回结果可知,新数组的每个元素值都是 0.0 ,说明
np.zeros_like
函数成功创建了一个元素全为 0 且形状与ones
一致的数组。
- 这行代码以数组
2.4.1.2 从现有数组生成
NumPy 中从现有数组生成新数组的方法:
- 函数介绍:
np.array(object, dtype)
:可以将输入的对象(如列表、元组等)转换为 NumPy 数组,dtype
参数可选,用于指定数组的数据类型。当输入对象本身就是 NumPy 数组时,它会创建一个新的数组,新数组和原数组的数据相同。np.asarray(a, dtype)
:将输入的对象转换为 NumPy 数组,若输入已经是 NumPy 数组且数据类型符合要求,则不会创建新的数组,而是返回原数组的引用(类似索引形式);若数据类型不匹配或输入不是 NumPy 数组,才会创建新数组。
- 示例讲解:
- 先通过
a = np.array([[1,2,3],[4,5,6]])
创建了一个二维数组a
。 a1 = np.array(a)
:使用np.array
对已有数组a
进行操作,会创建一个新的数组a1
,a1
和a
的数据内容一样。a2 = np.asarray(a)
:使用np.asarray
处理数组a
,由于a
已经是 NumPy 数组,这里不会真正创建新数组,a2
只是a
的一个引用,对a
或a2
中一个的修改会反映在另一个上。- a1相当于深拷贝,a2相当于浅拷贝,改变a的值a1不变而a2变
- 先通过
2.4.1.3 生成固定范围数组
NumPy 中生成固定范围数组的三种方法:
1. np.linspace(start, stop, num, endpoint)
- 功能:用于创建指定数量元素的等差数组。
- 参数详解:
start
:序列的起始值。stop
:序列的终止值。num
:要生成的等间隔样本数量,默认为 50。endpoint
:序列中是否包含stop
值,默认为True
。
- 示例:
np.linspace(0, 100, 11)
,这里起始值start
为 0,终止值stop
为 100,num
为 11,表示生成包含 11 个元素的数组。由于endpoint
采用默认值True
,所以数组中包含终止值 100。返回结果array([ 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100.])
,相邻元素差值为 10,是一个等差数组。
2. np.arange(start, stop, step, dtype)
- 功能:创建指定步长的等差数组。
- 参数详解:
start
:起始值(包含)。stop
:终止值(不包含)。step
:步长,默认值为 1。dtype
:数据类型,可选参数。
- 示例:
np.arange(10, 50, 2)
,起始值start
是 10,终止值stop
是 50,步长step
为 2。返回结果array([10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48])
,数组从 10 开始,以步长 2 递增,直到小于 50 为止。
3. np.logspace(start, stop, num)
- 功能:用于创建等比数列。
- 参数详解:
start
:序列起始值的对数(底数默认为 10),即10 ** start
为序列的起始值。stop
:序列终止值的对数(底数默认为 10),即10 ** stop
为序列的终止值。num
:要生成的等比数列数量,默认为 50。
- 示例:
np.logspace(0, 2, 3)
,这里start
为 0,stop
为 2,num
为 3。起始值是10 ** 0 = 1
,终止值是10 ** 2 = 100
,生成包含 3 个元素的等比数列。返回结果array([ 1., 10., 100.])
,相邻元素的比值为 10,是一个等比数列。
2.4.1.4 生成正态分布,均匀分布数组
正态分布创建方式
np.random.randn(d0, d1, ..., dn)
- 功能:从标准正态分布(均值为 0,标准差为 1)返回一个或多个样本值。参数
d0, d1, ..., dn
用于指定输出数组的形状。 - 示例:如
np.random.randn(2, 3)
会生成一个形状为 (2, 3) 的数组,数组中的元素都从标准正态分布中随机采样得到。
- 功能:从标准正态分布(均值为 0,标准差为 1)返回一个或多个样本值。参数
np.random.normal(loc=0.0, scale=1.0, size=None)(常用)
- 功能:从指定均值和标准差的正态分布中随机采样。
- 参数详解:
loc
:概率分布的均值,对应整个分布的中心,默认值为 0.0。scale
:概率分布的标准差,对应分布的宽度,scale
越大分布越矮胖,scale
越小分布越瘦高,默认值为 1.0。size
:输出的形状,默认为None
,此时只输出一个值;若为整数或整数元组,则输出对应形状的数组。
- 示例:
x1 = np.random.normal(1.75, 1, 100000000)
,这里指定均值loc
为 1.75,标准差scale
为 1,size
为 100000000,即生成 1 亿个均值为 1.75,标准差为 1 的正态分布数据。
np.random.standard_normal(size=None)
- 功能:返回指定形状的标准正态分布(均值为 0,标准差为 1)的数组。
- 示例:
np.random.standard_normal((3, 4))
会生成一个形状为 (3, 4) 的标准正态分布数组。
正态分布示例绘图部分
import matplotlib.pyplot as plt
import numpy as npx1 = np.random.normal(1.75, 1, 100000000)
plt.figure(figsize=(20, 10), dpi=100)
plt.hist(x1, 1000)
plt.show()
- 代码说明:
- 首先用
np.random.normal
生成数据x1
。 plt.figure(figsize=(20, 10), dpi=100)
创建一个画布,设置大小为 (20, 10) 英寸,分辨率为 100 像素 / 英寸。plt.hist(x1, 1000)
绘制直方图,将x1
的数据进行统计分组,这里设置了 1000 个 bins(区间),直观展示数据的分布状况。plt.show()
显示绘制的图像,可以看到数据呈现出以 1.75 为中心的正态分布形态。
- 首先用
均匀分布创建方式
np.random.rand(d0, d1, ..., dn)
- 功能:返回 [0.0, 1.0) 内的一组均匀分布的数。参数
d0, d1, ..., dn
用于指定输出数组的形状。 - 示例:
np.random.rand(2, 3)
会生成一个形状为 (2, 3) 的数组,元素在 [0.0, 1.0) 之间均匀分布。
- 功能:返回 [0.0, 1.0) 内的一组均匀分布的数。参数
np.random.uniform(low=0.0, high=1.0, size=None)(常用)
- 功能:从一个均匀分布
[low, high)
中随机采样,定义域是左闭右开,即包含low
,不包含high
。 - 参数详解:
low
:采样下界,默认值为 0.0。high
:采样上界,默认值为 1.0。注意是样本的上限不是X轴的size
:输出样本数目,为整数或元组类型,例如size=(m, n, k)
,则输出mnk
个样本,缺省时输出 1 个值。
- 示例:
x2 = np.random.uniform(-1, 1, 100000000)
,从 [-1, 1) 的均匀分布中采样 1 亿个数据。
- 功能:从一个均匀分布
np.random.randint(low, high=None, size=None, dtype='l')
- 功能:从一个均匀分布中随机采样,生成一个整数或 N 维整数数组。
- 参数详解:
low
:取值范围的下限。high
:若不为None
,取值范围是[low, high)
之间的随机整数;若为None
,则取值范围是[0, low)
之间的随机整数。size
:输出的形状,默认为None
,此时只输出一个值;若为整数或整数元组,则输出对应形状的数组。dtype
:输出数据的类型,默认是'l'
(长整型)。
- 示例:
np.random.randint(1, 10, (2, 3))
会生成一个形状为 (2, 3) 的数组,元素是 1(包含)到 10(不包含)之间的随机整数。
2.4.2ndarray的切片和索引
注意切片包前不包后
很简单,在ndarray中用,间隔表示即可即对象[切片或者索引,切片或者索引 ,切片或者索引 , 切片或者索引,.....],索引就是a:b表示。
2.4.3 形状的修改
1. ndarray.reshape(shape, order)
- 功能:返回一个具有相同数据域,但形状不一样的视图。原数组和新数组共享数据内存,所以使用后原数组发生变化,且不会对行、列进行互换。
order
参数可选,用于指定在内存中如何排列元素,常见取值有'C'
(按行优先,即 C 语言风格)和'F'
(按列优先,即 Fortran 语言风格),默认是'C'
。 - 注意事项:转换形状时,新形状的元素总数必须与原数组一致。
- 示例:
import numpy as np# 创建一个一维数组
stock_change = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])# 转换为5行4列的二维数组
new_array_1 = stock_change.reshape((5, 4))
print(new_array_1)# 使用-1自动计算维度,转换为2行10列的二维数组
new_array_2 = stock_change.reshape((-1, 10))
print(new_array_2)
在上述代码中,reshape((5, 4))
将stock_change
数组转换为 5 行 4 列的二维数组;reshape((-1, 10))
中-1
表示让 NumPy 自动计算该维度的大小,从而得到 2 行 10 列的二维数组,因为总元素数是 20,另一维是 10,所以这一维就是 2。
2. ndarray.resize(new_shape)
- 功能:直接修改数组本身的形状,修改后数组的元素个数需要和原来保持相同。同样不会对行、列进行互换。
- 示例:
import numpy as npstock_change = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])# 修改为5行4列的二维数组
stock_change.resize((5, 4))
print(stock_change.shape) # 输出 (5, 4)
print(stock_change)
执行resize((5, 4))
后,stock_change
数组本身的形状被修改为 5 行 4 列,后续再访问stock_change.shape
时,会得到新的形状(5, 4)
。
3. ndarray.T
- 功能:实现数组的转置,即将数组的行和列进行互换。
- 示例:
import numpy as npstock_change = np.array([[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],[13, 14, 15, 16],[17, 18, 19, 20]
])# 获取转置后的形状
transposed_shape = stock_change.T.shape
print(transposed_shape) # 输出 (4, 5)
print(stock_change.T)
在图片介绍的三种ndarray
形状修改方法中,ndarray.resize(new_shape)
会直接修改原数组的形状,数组内容也会相应按照新形状重新排布 ,对原数组影响明显;ndarray.reshape(shape, order)
返回的是原数组的一个视图,虽然数组数据共享,但它不改变原数组本身形状;ndarray.T
是转置操作,生成一个新的转置数组,原数组本身不受影响 。
2.4.4类型修改(对象.方法())
1. ndarray.astype(type)
- 功能:将数组中的元素类型转换为指定的
type
,并返回一个新的数组。原数组不会被修改,新数组和原数组的数据内容相同,但数据类型不同。type
可以是 NumPy 中的各种数据类型,如np.int32
、np.float64
等。 - 示例:
import numpy as np# 创建一个包含浮点数的数组
stock_change = np.array([1.1, 2.2, 3.3])
print("原数组:", stock_change)
print("原数组类型:", stock_change.dtype)# 将数组类型转换为np.int32
new_stock_change = stock_change.astype(np.int32)
print("转换后数组:", new_stock_change)
print("转换后数组类型:", new_stock_change.dtype)
在上述代码中,stock_change
原本是包含浮点数的数组,数据类型为float64
(默认)。通过astype(np.int32)
将其元素类型转换为 32 位整数,生成一个新数组new_stock_change
,原数组stock_change
保持不变。
2. ndarray.tostring([order])
或者 ndarray.tobytes([order])
- 功能:这两个方法功能基本相同,用于将数组中的原始数据以字节的形式转换为 Python 字节对象。
order
参数可选,用于指定在内存中读取元素的顺序,常见取值有'C'
(按行优先,即 C 语言风格)和'F'
(按列优先,即 Fortran 语言风格),默认是'C'
。 - 示例:
import numpy as np# 创建一个二维数组
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[12, 3, 34], [5, 6, 7]]])
print("原数组:", arr)# 将数组转换为字节对象
byte_obj = arr.tostring()
print("字节对象:", byte_obj)
print("字节对象类型:", type(byte_obj))
2.4.5数组去重
NumPy 中用于数组去重的np.unique()
函数
函数功能
np.unique()
函数用于去除数组中的重复元素,并返回一个包含唯一元素的新数组,且新数组中的元素会按照升序排列。它适用于一维数组,对于多维数组,会先将其展平(flatten)后再进行去重操作。
代码示例讲解
import numpy as np# 创建一个二维数组
temp = np.array([[1, 2, 3, 4], [3, 4, 5, 6]])# 使用np.unique()函数去重
result = np.unique(temp)
print(result)
在上述代码中:
- 首先创建了一个二维数组
temp
,其中包含重复的元素,如3
和4
。 - 然后调用
np.unique(temp)
对temp
数组进行去重操作。由于temp
是二维数组,np.unique()
会先将其展平为一维数组[1, 2, 3, 4, 3, 4, 5, 6]
,再去除重复元素,并按升序排列,最终返回的结果是array([1, 2, 3, 4, 5, 6])
。
使用np.unique()
函数不会修改原数组。如图片中的示例代码,创建temp
数组后调用np.unique(temp)
,只是基于temp
数组的数据生成一个去重且排序后的新数组并返回,temp
数组本身的元素和结构都保持不变 。可以通过下面补充的代码验证:
import numpy as np
temp = np.array([[1, 2, 3, 4], [3, 4, 5, 6]])
original_temp = temp.copy() # 复制一份原数组
result = np.unique(temp)
print("原数组:", temp)
print("原数组与复制的数组是否相等:", np.array_equal(temp, original_temp))
上述代码中,提前复制一份原数组original_temp
,在调用np.unique(temp)
后,对比原数组temp
和original_temp
,会发现二者相等,说明np.unique()
未对原数组做修改。
2.5ndarray运算
2.5.1. 逻辑运算
import numpy as np# 生成10名同学,5门功课的数据
score = np.random.randint(40, 100, (10, 5))# 取出最后4名同学的成绩,用于逻辑判断
test_score = score[6:, 0:5]# 逻辑判断,如果成绩大于60就标记为True,否则为False
bool_result = test_score > 60
print("逻辑判断结果:\n", bool_result)# BOOL赋值,将满足条件的设置为指定的值-布尔索引
test_score[test_score > 60] = 1
print("赋值后的成绩:\n", test_score)
- 首先使用
np.random.randint(40, 100, (10, 5))
生成一个形状为(10, 5)
的二维数组score
,表示 10 名同学 5 门功课的成绩,成绩范围在 40 到 100 之间。 - 通过切片
score[6:, 0:5]
取出最后 4 名同学的成绩,存储在test_score
中。 - 使用
test_score > 60
进行逻辑判断,得到一个布尔类型的数组bool_result
,其中成绩大于 60 的位置为True
,否则为False
。 - 利用布尔索引
test_score[test_score > 60] = 1
,将test_score
中成绩大于 60 的元素赋值为 1。
2.5.2. 通用判断函数
np.all()
import numpy as npscore = np.random.randint(40, 100, (10, 5))
# 判断前两名同学的成绩是否全及格
all_result = np.all(score[0:2, :] > 60)
print("np.all判断结果:", all_result)
np.all()
函数用于判断数组中的所有元素是否都满足指定条件。这里np.all(score[0:2, :] > 60)
判断前两名同学(第一维和第二维切片0:2
)的所有成绩(第二维取全部:
)是否都大于 60。如果所有元素都满足条件,返回True
,否则返回False
。
np.any()
import numpy as npscore = np.random.randint(40, 100, (10, 5))
# 判断前两名同学的成绩是否有大于80分的
any_result = np.any(score[0:2, :] > 80)
print("np.any判断结果:", any_result)
np.any()
函数用于判断数组中是否至少有一个元素满足指定条件。np.any(score[0:2, :] > 80)
判断前两名同学的成绩中是否存在大于 80 分的。如果有至少一个元素满足条件,返回True
,否则返回False
。
2.5.3. np.where
(三元运算符)
简单使用
import numpy as npscore = np.random.randint(40, 100, (10, 5))
# 取前四名同学,前四门课程的成绩
temp = score[:4, :4]
# 成绩中大于60的置为1,否则为0
where_result = np.where(temp > 60, 1, 0)
print("np.where简单使用结果:\n", where_result)
np.where()
函数根据条件返回不同的值。np.where(temp > 60, 1, 0)
表示如果temp
中的元素大于 60,就返回 1,否则返回 0。
结合复合逻辑
当需要进行复合逻辑判断时,结合np.logical_and
(逻辑与)和np.logical_or
(逻辑或)函数使用。np.logical_and(temp > 60, temp < 90)
判断元素是否既大于 60 又小于 90,np.logical_or(temp > 90, temp < 60)
判断元素是否大于 90 或者小于 60 ,然后np.where
根据这些复合条件返回相应的值。
import numpy as npscore = np.random.randint(40, 100, (10, 5))
temp = score[:4, :4]
# 成绩中大于60且小于90的换为1,否则为0
where_and_result = np.where(np.logical_and(temp > 60, temp < 90), 1, 0)
print("np.where结合logical_and结果:\n", where_and_result)# 成绩中大于90或小于60的换为1,否则为0
where_or_result = np.where(np.logical_or(temp > 90, temp < 60), 1, 0)
print("np.where结合logical_or结果:\n", where_or_result)
2.5.4. 统计运算
min(a, axis)
:返回数组a
的最小值,若指定axis
参数(axis=0
表示按列,axis=1
表示按行),则返回沿指定轴的最小值。max(a, axis)
:返回数组a
的最大值,同样可根据axis
参数沿指定轴返回最大值。median(a, axis)
:计算数组a
沿指定轴的中位数。mean(a, axis, dtype)
:计算数组a
沿指定轴的算术平均值,dtype
参数可选,用于指定计算时的数据类型。std(a, axis, dtype)
:计算数组a
沿指定轴的标准差。var(a, axis, dtype)
:计算数组a
沿指定轴的方差。
学生成绩统计运算案例
import numpy as np# 生成10名同学,5门功课的数据
score = np.random.randint(40, 100, (10, 5))# 取前四名学生的成绩
temp = score[:4, 0:5]# 计算各科成绩的最大值
max_scores = np.max(temp, axis=0)
print("前四名学生, 各科成绩的最大分:", max_scores)# 计算各科成绩的最小值
min_scores = np.min(temp, axis=0)
print("前四名学生, 各科成绩的最小分:", min_scores)# 计算各科成绩的标准差(衡量波动情况)
std_scores = np.std(temp, axis=0)
print("前四名学生, 各科成绩波动情况:", std_scores)# 计算各科成绩的平均分
mean_scores = np.mean(temp, axis=0)
print("前四名学生, 各科成绩的平均分:", mean_scores)
- 首先使用
np.random.randint(40, 100, (10, 5))
生成一个形状为(10, 5)
的二维数组score
,代表 10 名学生 5 门课程的成绩,成绩范围在 40 到 100 之间。 - 通过切片
score[:4, 0:5]
获取前四名学生的成绩,存储在temp
中。 - 分别调用
np.max(temp, axis=0)
、np.min(temp, axis=0)
、np.std(temp, axis=0)
和np.mean(temp, axis=0)
,计算出这四名学生各科成绩的最大值、最小值、标准差和平均分。这里axis=0
表示按列统计,即对每一门课程的成绩进行统计。
获取最值对应索引的函数
np.argmax(a, axis)
:返回数组a
沿指定轴(axis=0/1)的最大值的索引。np.argmin(a, axis)
:返回数组a
沿指定轴的最小值的索引。
查找某科最高分对应的学生案例
import numpy as np# 生成10名同学,5门功课的数据
score = np.random.randint(40, 100, (10, 5))# 取前四名学生的成绩
temp = score[:4, 0:5]# 获取各科成绩最高分对应的学生下标
max_indexes = np.argmax(temp, axis=0)
print("前四名学生, 各科成绩最高分对应的学生下标:", max_indexes)
2.6数组的运算
1. 数组与数的运算
import numpy as np# 创建一个二维数组
arr = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])# 数组与数相加
result1 = arr + 1
print("数组与1相加的结果:\n", result1)# 数组与数相除
result2 = arr / 2
print("数组与2相除的结果:\n", result2)# 创建一个Python列表
a = [1, 2, 3, 4, 5]# 列表与数相乘
result3 = a * 3
print("列表与3相乘的结果:", result3)
- 在 NumPy 中,数组与数的运算会将数应用到数组的每个元素上。如
arr + 1
会把数组arr
中的每个元素都加 1,arr / 2
会将每个元素除以 2 。 - 对比之下,Python 列表与数相乘(如
a * 3
),是将列表中的元素重复指定的次数,和 NumPy 数组的运算规则不同。
2. 数组与数组的运算
import numpy as np# 创建两个二维数组
arr1 = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])
arr2 = np.array([[1, 2, 3, 4], [3, 4, 5, 6]])
一般情况下,两个数组进行运算要求形状(shape)完全相同,图片中的arr1
和arr2
形状不同,直接运算会报错。但如果满足广播机制也可以进行运算
3. 广播机制
import numpy as np# 创建两个形状不同的数组
arr1 = np.array([[0], [1], [2], [3]])
print("arr1的形状:", arr1.shape)arr2 = np.array([1, 2, 3])
print("arr2的形状:", arr2.shape)# 数组相加
result = arr1 + arr2
print("相加的结果:\n", result)
- 当数组形状不完全相同时,广播机制会发挥作用。
arr1
形状是(4, 1)
,arr2
形状是(1,3)
。 - 广播机制会扩展数组,使它们的形状兼容以便进行运算。这里
arr1
会在列方向扩展,变为(4,3)arr2
会在行方向扩展,变为(4,3)最终二者都扩展为(4, 3)
的形状再进行对应元素相加。 - 广播机制满足的条件:一是数组的某一维度等长;二是其中一个数组的某一维度为 1 。若不满足这些条件,如
A
(1 维数组长度为 10)、B
(1 维数组长度为 12)、A
(2 维数组2×1
)、B
(3 维数组8×4×3
),则数组不匹配,无法通过广播机制运算。进行对比时要一个一个对比,每个位置必需都满足条件比如2*4*1与2*1*6满足因为(1,6)(4,1)(2,2)都满足条件。注意如果维度不同,低维的按1处理即可。
2.7矩阵的运算
2.7.1. 矩阵乘法 API 函数介绍
np.matmul
:用于执行矩阵乘法运算。它遵循严格的矩阵乘法规则,对于二维数组,就是标准的矩阵乘法;对于更高维度的数组,它会把最后两个维度视为矩阵进行乘法运算,而前面的维度保持不变。np.dot
:也可以进行矩阵乘法运算,但它的行为在处理一维数组和高维数组时,与np.matmul
略有不同。对于二维数组,np.dot
和np.matmul
的功能类似,都是执行标准的矩阵乘法;对于一维数组,np.dot
计算的是它们的内积。
2.7.2. 代码示例讲解
import numpy as np# 创建一个二维数组a,形状为(7, 2)
a = np.array([[80, 86],[82, 80],[85, 78],[90, 90],[82, 90],[78, 80],[92, 94]])# 创建一个二维数组b,形状为(2, 1)
b = np.array([[0.7], [0.3]])# 使用np.matmul进行矩阵乘法
result_matmul = np.matmul(a, b)
print("使用np.matmul的结果:\n", result_matmul)# 使用np.dot进行矩阵乘法
result_dot = np.dot(a, b)
print("使用np.dot的结果:\n", result_dot)
- 首先创建了两个数组
a
和b
,a
是一个形状为(7, 2)
的二维数组,b
是一个形状为(2, 1)
的二维数组。在矩阵乘法中,要求第一个矩阵的列数等于第二个矩阵的行数,这里a
的列数为 2,b
的行数为 2,满足矩阵乘法的条件。 - 然后分别使用
np.matmul(a, b)
和np.dot(a, b)
进行矩阵乘法运算。从输出结果可以看到,在这种二维数组且满足矩阵乘法规则的情况下,np.matmul
和np.dot
得到的结果是相同的。这是因为对于二维数组的标准矩阵乘法,这两个函数的功能一致 。但在处理一维数组或更复杂的高维数组时,它们的表现会有差异,例如当处理一维数组时,np.dot
计算内积,而np.matmul
则会报错,因为它要求输入至少是二维的矩阵形式 。