NumPy是一个开源的Python科学计算基础库,主要用于对大量数据进行高效存储和计算,提供了许多向量和矩阵操作,能够帮助轻松完成科学与工程中常用的各种计算,不仅方便易用而且效率更高。
官网:numpy.org
源代码:github numpy
import numpy as np
1 NumPy数组基础
PyTorch张量的语法与NumPy数组基本相同或相似,具体区别详见下文。
1.1 数据类型
一个NumPy数组只容纳一种数据类型,可分为整数型数组、浮点型数组和布尔型数组等。初始化时可通过设置dtype
属性来指定数据类型。
同化定理:往整数型数组里插入浮点数,该浮点数会自动被截断为整数;往浮点型数组里插入整数,该整数会自动升级为浮点数。
想实现整数型数组和浮点型数组的相互转换,可以使用.astype()
方法指定转换类型(PyTorch中为.type()
)。整数型数组在运算过程中升级为浮点型数组。
arr1 = np.array([1, 2, 3]) # 元素若都是整数,则为整数型数组
arr2 = np.array([1.0, 2, 3]) # 内含浮点数,则为浮点型数组
print(arr2.astype(int)) # 浮点型降级
print(arr1 + 10.0) # 整数型进行各种浮点运算会升级
print(arr1 / 1) # 整数型遇到除法也会升级(即使除以整数)
[1 2 3]
[11. 12. 13.]
[1. 2. 3.]
1.2 形状参数(shape)
不同维度的数组在外形上的表现为:$n$ 维数组使用 $n$ 层中括号表示。可以用形状参数来描述数组的形状:
- 一维数组的形状参数:
x
或(x,)
【例】[1, 2, 3]
的形状为3
或[3,]
- 二维数组的形状参数:
(x, y)
【例】[[1, 2, 3]]
的形状为(1, 3)
- 三维数组的形状参数:
(x, y, z)
【例】[[[1, 2, 3]]]
的形状为(1, 1, 3)
使用数组的shape
属性查看形状参数。
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print(arr, arr.shape)
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]] (3, 4)
本文将一维数组称为向量, 二维数组称为矩阵。
可使用数组的重塑方法.reshape()
(或.resize()
来直接修改数组)对数组进行重塑,需要传入重塑后的形状参数(shape)。给定了其他维度的数值,剩下一个维度可以填-1
,让其自动计算。
1.3 数组初始化函数
1.3.1 创建指定数组:np.array()
当明确知道数组每一个元素的具体数值时,使用np.array()
函数将Python列表转化为NumPy数组。
arr1 = np.array([1, 2, 3]) # 创建向量
arr2 = np.array([[1, 2, 3]]) # 创建行矩阵
arr3 = np.array([[1], [2], [3]]) # 创建列矩阵
arr4 = np.array([[1, 2, 3], [4, 5, 6]]) # 创建矩阵
print(arr1, '\n')
print(arr2, '\n')
print(arr3, '\n')
print(arr4)
[1 2 3]
[[1 2 3]]
[[1]
[2]
[3]]
[[1 2 3]
[4 5 6]]
PyTorch中的torch.tensor()
用同样方式创建指定张量。NumPy的 $n$ 维数组与PyTorch的 $n$ 阶张量可相互转换:
# 数组arr转为张量ts
ts = torch.tensor(arr);
# 张量ts转为数组arr
arr = np.array(ts)
1.3.2 创建递增数组:np.arange()
使用np.arange()
函数创建递增数组,可设置左闭右开区间的两端点以及步长(默认步长为1)。(同Python的range()
函数)
arr1 = np.arange(10) # [0, 10)
arr2 = np.arange(-8, 8) # [-8, 8)
arr3 = np.arange(1, 21, 2) # [1, 21), 步长为2
print(arr1)
print(arr2)
print(arr3)
[0 1 2 3 4 5 6 7 8 9]
[-8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7]
[ 1 3 5 7 9 11 13 15 17 19]
1.3.3 创建同值数组:np.zeros()、np.ones()
使用np.zeros()
函数创建零向量/全0数组,使用np.ones()
函数创建单位向量/全1数组。给全1矩阵乘以标量即得全为任意指定数值的矩阵。
arr1 = np.zeros(5) # 形状为5的零向量
arr2 = np.ones((1, 3)) # 形状为(1, 3)的全1矩阵
arr3 = 3.14 * np.ones((3, 4)) # 形状为(3, 4)的元素全为3.14的矩阵
print(arr1, '\n')
print(arr2, '\n')
print(arr3)
[0. 0. 0. 0. 0.]
[[1. 1. 1.]]
[[3.14 3.14 3.14 3.14]
[3.14 3.14 3.14 3.14]
[3.14 3.14 3.14 3.14]]
1.3.4 创建随机数组:np.random系列
使用np.random
系列函数创建随机数组
np.random.random()
:返回0~1均匀分布的浮点型随机数组,需传入形状参数。可进一步操作实现生成任意范围内的随机浮点数。(PyTorch中为torch.rand()
)
arr1 = np.random.random(10)
arr2 = (100 - 60) * np.random.random((3, 3)) + 60 # 创建60~100均匀分布的随机数组
print(arr1, '\n')
print(arr2)
[0.14008334 0.85222803 0.2760929 0.66515642 0.15214672 0.27926126
0.62884946 0.58995347 0.63499827 0.45314506]
[[92.22277485 95.13300136 66.32344792]
[65.95501162 81.82263033 94.09181926]
[71.07830426 72.96512988 82.15612346]]
np.random.randint()
:创建整数型随机数组,在指定形状参数之前还需额外输入范围参数。(PyTorch中为torch.randint()
,且不接纳一维向量)
arr1 = np.random.randint(10, 100, (3, 5)) # 元素为[10, 100)上的整数型随机数
print(arr1)
[[50 16 26 95 87]
[21 61 68 42 43]
[43 99 13 10 31]]
np.random.normal()
:生成服从正态分布的随机数组,在指定形状参数之前还需额外输入正态参数,即均值、方差。(PyTorch中为torch.normal()
,且不接纳一维向量)np.random.randn()
:直接生成服从标准正态分布(均值为0、方差为1)的随机数组,只需指定形状参数。(PyTorch中为torch.randn()
)
arr1 = np.random.randn(3, 4) # 等价于 np.random.normal(0, 1, (3, 4))
print(arr1)
[[ 0.69340209 -1.03197149 0.04238088 -1.28391985]
[ 1.32393424 -0.11255891 -0.01172114 -1.17029623]
[ 1.67580726 2.83716736 -0.64356777 2.60345476]]
1.3.5 其他常用的创建方法
np.empty(shape)
:内存创建。分配数组大小内存,而不产生实际值。具有相同效果的还有有empty_like()
函数。np.full(shape, val)
:填充创建。指定数组形状,再指定一个数填充入该结构中。np.linspace(start, end, num=50)
:等差数组创建,生成从start
到end
上的num
个数的等差数列。参考arange()
函数。np.logspace(start, end, num=50, base=10)
:等比数组创建,生成从start * base
到end * base
上的num
个数的等比数列。参考arange()
函数。ones_like(a)
、zeros_like(a)
、full_like(a, val)
:根据所传入数组的形状创建
2 数组的索引
2.1 访问数组元素
与Python列表基本一致,访问NumPy数组元素时使用中括号,索引由0开始。
arr1 = np.arange(1, 10)
print(arr1)
print(arr1[3], arr1[-1])
arr1[5] = 99.8 # 元素可被修改;浮点数插入到整数型数组时会被截断
print(arr1)
[1 2 3 4 5 6 7 8 9]
4 9
[ 1 2 3 4 5 99 7 8 9]
访问多维数组时,只使用1个中括号,各维索引之间用逗号分隔即可。
arr1 = np.arange(1, 7).reshape(2, -1)
print(arr1)
print(arr1[0, 2], arr1[1, -2])
arr1[1, 1] = -10.4
print(arr1)
[[1 2 3]
[4 5 6]]
3 5
[[ 1 2 3]
[ 4 -10 6]]
2.2 花式索引
花式索引(Fancy Indexing)一次性取出多个元素组成数组。索引形式上可视为将单一索引的标量改为多个索引的向量。
arr1 = np.arange(0, 100, 10)
print(arr1)
print(arr1[[0, 2]])
[ 0 10 20 30 40 50 60 70 80 90]
[ 0 20]
矩阵的花式索引操作同上,注意索引配对。
arr1 = np.arange(1, 17).reshape(4, 4)
print(arr1, '\n')
print(arr1[[0, 1], [0, 1]], '\n')
print(arr1[[0, 1, 2], [2, 1, 0]], '\n')
arr1[[0, 1, 2, 3], [3, 2, 1, 0]] = 100 # 批量修改元素
print(arr1)
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]]
[1 6]
[3 6 9]
[[ 1 2 3 100]
[ 5 6 100 8]
[ 9 100 11 12]
[100 14 15 16]]
2.3 访问数组切片
NumPy数组的切片操作与Python列表完全一致。
# 向量切片
arr1 = np.arange(10)
print(arr1)
print(arr1[1:4])
print(arr1[3:])
print(arr1[:-2])
print(arr1[1:-1:2])
[0 1 2 3 4 5 6 7 8 9]
[1 2 3]
[3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7]
[1 3 5 7]
当提取矩阵的某一个单独的列时,其结果为一个向量(因为降维)。
# 矩阵切片
arr1 = np.arange(1, 21).reshape(4, 5)
print(arr1, '\n')
print(arr1[1:3, 1:-1], '\n')
print(arr1[::3, ::2], '\n')
print(arr1[2, :], '\n') # 提取下标2的行,等价于arr[2]
print(arr1[:, 2], '\n') # 提取下标2的列(同样获得向量)
print(arr1[:, 2].reshape(-1, 1)) # 将上一行所得(列)向量升级为列矩阵
[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]]
[[ 7 8 9]
[12 13 14]]
[[ 1 3 5]
[16 18 20]]
[11 12 13 14 15]
[ 3 8 13 18]
[[ 3]
[ 8]
[13]
[18]]
与Python列表和Matlab不同,NumPy数组的切片仅仅是原数组的一个视图,即NumPy切片并不会创建新的变量。
可以使用.copy()
方法创建新变量(PyTorch中为 .clone()
)。
arr1 = np.arange(10)
arr2 = arr1[2:7].copy() + 10
print(arr1)
print(arr2)
[0 1 2 3 4 5 6 7 8 9]
[12 13 14 15 16]
3 数组的变形
3.1 转置: .T
数组转置只需调用对象的属性T
,其只对矩阵有效,因此遇到向量要先将其转化为矩阵。
arr1 = np.arange(1, 13).reshape(2, -1)
print(arr1, '\n')
print(arr1.T)
[[ 1 2 3 4 5 6]
[ 7 8 9 10 11 12]]
[[ 1 7]
[ 2 8]
[ 3 9]
[ 4 10]
[ 5 11]
[ 6 12]]
3.2 翻转:np.flipud()、np.fliplr()
使用函数np.flipud()
上下翻转(up-down)、np.fliplr()
左右翻转(left-right)。
其中向量只能上下翻转,因为此处的向量是竖着排的。
# 向量翻转
arr1 = np.arange(10)
print(arr1)
arr_ud = np.flipud(arr1)
print(arr_ud)
[0 1 2 3 4 5 6 7 8 9]
[9 8 7 6 5 4 3 2 1 0]
# 矩阵翻转
arr1 = np.arange(1, 21).reshape(4, -1)
print(arr1, '\n')
arr_ud = np.flipud(arr1)
arr_lr = np.fliplr(arr1)
print(arr_ud, '\n')
print(arr_lr, '\n')
[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]]
[[16 17 18 19 20]
[11 12 13 14 15]
[ 6 7 8 9 10]
[ 1 2 3 4 5]]
[[ 5 4 3 2 1]
[10 9 8 7 6]
[15 14 13 12 11]
[20 19 18 17 16]]
3.3 重塑:.reshape()
同1.2中所述,使用数组的重塑方法reshape()
对数组进行重塑,需要传入重塑后的形状参数(shape)。
给定了其他维度的数值,剩下一个维度可以填-1
,让其自动计算。
# 向量升级
arr1 = np.arange(10)
arr2 = arr1.reshape((1, -1)) # 向量升级为矩阵
print(arr1)
print(arr2)
[0 1 2 3 4 5 6 7 8 9]
[[0 1 2 3 4 5 6 7 8 9]]
# 矩阵降级
arr1 = np.arange(10).reshape(2,5)
arr2 = arr1.reshape(-1) # 矩阵降级为向量
print(arr1)
print(arr2)
[[0 1 2 3 4]
[5 6 7 8 9]]
[0 1 2 3 4 5 6 7 8 9]
.reshape()
不会修改原数组,会返回一个新数组。若想直接改变原数据可使用.resize()
方法。
3.4 展平:.flatten()
方法.flatten()
为特殊的重塑,将多维数组展平成一维数组,相当于.reshape(-1)
。广泛应用于神经网络设计中(如从卷积层到全连接层之间的过渡)。
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr, '\n')
flattened_arr = arr.flatten()
print(flattened_arr)
[[1 2 3]
[4 5 6]]
[1 2 3 4 5 6]
.flatten()
不会实际修改数组,会返回一个新数组。若想直接改变原数据可使用.ravel()
方法。
3.5 拼接:np.concatenate()
使用函数np.concatenate()
来拼接向量或矩阵,传入含有待拼接对象的列表.(PyTorch中为torch.cat()
)
# 向量拼接
arr1 = np.array([1, 2, 3])
arr2 = np.array([4 ,5 ,6])
print(arr1)
print(arr2)
arr3 = np.concatenate([arr1, arr2])
print(arr3)
[1 2 3]
[4 5 6]
[1 2 3 4 5 6]
拼接矩阵时可设置参数axis
(默认为0),axis=x
意为沿轴x,需保证该轴吻合。
# 矩阵拼接
arr1 = np.arange(1, 7).reshape(2, -1)
arr2 = np.arange(7, 13).reshape(2, -1)
print(arr1, '\n')
print(arr2, '\n')
arr3 = np.concatenate([arr1, arr2]) # 默认 axis=0
arr4 = np.concatenate([arr1, arr2], axis=1)
print(arr3, '\n')
print(arr4, '\n')
[[1 2 3]
[4 5 6]]
[[ 7 8 9]
[10 11 12]]
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
[[ 1 2 3 7 8 9]
[ 4 5 6 10 11 12]]
注意向量和矩阵不能进行拼接,需先将向量升级为矩阵。
3.6 分裂:np.split()
使用函数np.split()
来分裂数组,返回所有分裂所得结果。除传入原数组外,还需传入截断位置的索引列表。
每个截断位置被归至下一段数组,符合左开右闭。
# 向量分裂
arr = np.arange(10,100,10)
print(arr)
arr1, arr2, arr3 = np.split(arr, [2, 8])
print(arr1)
print(arr2)
print(arr3)
[10 20 30 40 50 60 70 80 90]
[10 20]
[30 40 50 60 70 80]
[90]
矩阵的分裂同样可以设置维度axis
(参考4.4拼接),分裂出来的均为矩阵。
# 矩阵分裂
arr = np.arange(10,130,10).reshape(3, -1)
print(arr, '\n')
arr1, arr2 = np.split(arr, [1]) # 默认 axis=0
print(arr1, '\n')
print(arr2, '\n')
arr3, arr4, arr5 = np.split(arr, [1, 2], axis=1)
print(arr3, '\n')
print(arr4, '\n')
print(arr5)
[[ 10 20 30 40]
[ 50 60 70 80]
[ 90 100 110 120]]
[[10 20 30 40]]
[[ 50 60 70 80]
[ 90 100 110 120]]
[[10]
[50]
[90]]
[[ 20]
[ 60]
[100]]
[[ 30 40]
[ 70 80]
[110 120]]
4 数组的运算
NumPy的运算符与Python的基本运算符基本一致。执行基本运算时为按元素运算。
4.1 数组与系数的运算
数组与系数运算,为数组的每一个元素与该标量系数做运算。
arr = np.arange(1,10)
print(arr, '\n')
print(arr + 10)
print(arr - 10)
print(arr * 10)
print(arr / 10)
print(arr ** 2) # 乘方
print(arr // 3) # 取整
print(arr % 3)
[1 2 3 4 5 6 7 8 9]
[11 12 13 14 15 16 17 18 19]
[-9 -8 -7 -6 -5 -4 -3 -2 -1]
[10 20 30 40 50 60 70 80 90]
[0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
[ 1 4 9 16 25 36 49 64 81]
[0 0 1 1 1 2 2 2 3]
[1 2 0 1 2 0 1 2 0]
4.2 同维度数组的运算
同维度数组的运算,为对应元素之间的运算,即按元素运算。
arr1 = np.arange(-1, -6, -1)
arr2 = -arr1
print(arr1)
print(arr2, '\n')
print(arr1 + arr2)
print(arr1 - arr2)
print(arr1 * arr2) # 按元素乘法
print(arr1 / arr2)
print(arr1 ** arr2)
[-1 -2 -3 -4 -5]
[1 2 3 4 5]
[0 0 0 0 0]
[ -2 -4 -6 -8 -10]
[ -1 -4 -9 -16 -25]
[-1. -1. -1. -1. -1.]
[ -1 4 -27 256 -3125]
4.3 广播
两个不同形状的数组做按元素运算时,低维数组将升级为高维,每一维的长度延展至两者较长的长度,使得双方适配。
【例1】向量被广播:当一个形状为(x, y)
的矩阵与一个向量做运算时,要求该向量的形状必须为y
。运算时该向量会自动升级成形状为(1, y)
的行矩阵,再自动被广播为形状为(x,y)
的矩阵。
# 向量被广播
arr1 = np.array([-100,0,100])
arr2 = np.random.random((5, 3))
print(arr1)
print(arr2, '\n')
print(arr1 * arr2)
[-100 0 100]
[[0.41943684 0.88496282 0.2365987 ]
[0.65314971 0.68784876 0.13543705]
[0.86278741 0.97630806 0.31234621]
[0.52350008 0.19988783 0.86560187]
[0.15728886 0.35476424 0.48020136]]
[[-41.94368414 0. 23.65987005]
[-65.31497128 0. 13.54370536]
[-86.27874077 0. 31.23462061]
[-52.35000848 0. 86.56018672]
[-15.72888642 0. 48.02013556]]
【例2】列矩阵被广播:当一个形状为(x, y)
的矩阵与一个列矩阵做运算时,要求该列矩阵的形状必须为(x, 1)
。运算时该列矩阵会自动被广播为形状为(x, y)
的矩阵。
# 列矩阵被广播
arr1 = np.arange(3).reshape(3, 1)
arr2 = np.ones((3, 5))
print(arr1, '\n')
print(arr2, '\n')
print(arr1 * arr2)
[[0]
[1]
[2]]
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
[[0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1.]
[2. 2. 2. 2. 2.]]
【例3】行矩阵与列矩阵同时被广播:当一个形状为(1, y)
的行矩阵(或形状为y
的向量)与一个形状为(x, 1)
的列矩阵做运算时,它们都会被自动广播为形状为(x, y)
的矩阵。
# 行矩阵与列矩阵同时被广播
arr1 = np.arange(3)
arr2 = np.arange(3).reshape(3,1)
print(arr1, '\n')
print(arr2, '\n')
print(arr1 * arr2)
[0 1 2]
[[0]
[1]
[2]]
[[0 0 0]
[0 1 2]
[0 2 4]]
4.4 常用函数
4.4.1 矩阵乘法:np.dot()
使用函数np.dot()
来执行矩阵乘法。该函数会将作为左/右操作数的向量自动纠正为线代中的行/列向量。(PyTorch中为torch.matmul()
,且该函数有广播机制)
向量乘向量(点积,PyTorch中专用torch.dot()
)
# 向量乘向量
arr1 = np.arange(5)
arr2 = np.arange(5)
print(arr1)
print(arr2)
print(np.dot(arr1, arr2))
[0 1 2 3 4]
[0 1 2 3 4]
30
向量乘矩阵
# 向量乘矩阵
arr1 = np.arange(15).reshape(3,5)
arr2 = np.arange(5)
print(arr1, '\n')
print(arr2, '\n')
print(np.dot(arr1, arr2))
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
[0 1 2 3 4]
[ 30 80 130]
矩阵乘向量(PyTorch中专用torch.mv()
)
# 矩阵乘向量
arr1 = np.arange(3)
arr2 = np.arange(12).reshape(3,-1)
print(arr1, '\n')
print(arr2, '\n')
print(np.dot(arr1, arr2)) # arr1自动转为行向量
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/d64a41a019974e2ebd8b35a1e7039bfb.png =165x)
矩阵乘矩阵(PyTorch中专用torch.mm()
)
# 矩阵乘矩阵
arr1 = np.arange(10).reshape(5,2)
arr2 = np.arange(16).reshape(2,8)
print(arr1, '\n')
print(arr2, '\n')
print(np.dot(arr1, arr2))
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
[[ 0 1 2 3 4 5 6 7]
[ 8 9 10 11 12 13 14 15]]
[[ 8 9 10 11 12 13 14 15]
[ 24 29 34 39 44 49 54 59]
[ 40 49 58 67 76 85 94 103]
[ 56 69 82 95 108 121 134 147]
[ 72 89 106 123 140 157 174 191]]
4.4.2 数学函数
以下常用的数学函数同样均执行按元素运算。
- 绝对值函数:
np.abs()
x = np.array([-10, 0, 10])
print("x:\t\t", x)
print("abs(x):\t", np.abs(x))
x: [-10 0 10]
abs(x): [10 0 10]
- 三角函数:
np.sin()
、np.cos()
、np.tan()
……
x = np.arange(3) * np.pi / 2
print("x:\t\t", x)
print("sin(x):\t", np.sin(x))
print("cos(x):\t", np.cos(x))
print("tan(x):\t", np.tan(x))
x: [0. 1.57079633 3.14159265]
sin(x): [0.0000000e+00 1.0000000e+00 1.2246468e-16]
cos(x): [ 1.000000e+00 6.123234e-17 -1.000000e+00]
tan(x): [ 0.00000000e+00 1.63312394e+16 -1.22464680e-16]
- 指数函数:
np.exp()
($e^x$),或直接用**
运算符实现任意底数的指数幂
(PyTorch中的torch.exp()
必须传入张量)
x = np.arange(1, 5)
print("x:\t\t", x)
print("e^x:\t", np.exp(x))
print("2^x:\t", 2 ** x)
print("10^x:\t", 10 ** x)
x: [1 2 3 4]
e^x: [ 2.71828183 7.3890561 20.08553692 54.59815003]
2^x: [ 2 4 8 16]
10^x: [ 10 100 1000 10000]
- 对数函数:
np.log()
($\log x$)等,可由换底公式实现任意底数的对数
(PyTorch中的torch.log()
等必须传入张量)
x = np.array([1, 10, 100, 1000])
print("x:\t\t\t", x)
print("log(x):\t\t", np.log(x))
print("log2(x):\t", np.log2(x)) # 等价于 np.log(x) / np.log(2)
print("log10(x):\t", np.log10(x)) # 等价于 np.log(x) / np.log(10)
x: [ 1 10 100 1000]
log(x): [0. 2.30258509 4.60517019 6.90775528]
log2(x): [0. 3.32192809 6.64385619 9.96578428]
log10(x): [0. 1. 2. 3.]
4.4.3 聚合函数
使用聚合函数可以用于降维,均可设置axis
属性,axis=x
时的操作为沿轴x。
- 最大值函数
np.max()
、最小值函数np.min()
arr = np.random.random((2, 3))
print(arr)
print("沿轴0(行)求最大值:", np.max(arr, axis=0))
print("沿轴1(列)求最大值:", np.max(arr, axis=1))
print("整体求最大值:", np.max(arr))
[[0.70213283 0.55328389 0.15951074]
[0.43021584 0.55320289 0.33508742]]
沿轴0(行)求最大值: [0.70213283 0.55328389 0.33508742]
沿轴1(列)求最大值: [0.70213283 0.55320289]
整体求最大值: 0.7021328254530188
- 求和函数
np.sum()
、求积函数np.prod()
arr = np.arange(10).reshape(2, 5)
print(arr)
print("沿轴0(行)求最和:", np.sum(arr, axis=0))
print("沿轴1(列)求最和:", np.sum(arr, axis=1))
print("整体求和:", np.sum(arr))
[[0 1 2 3 4]
[5 6 7 8 9]]
沿轴0(行)求最和: [ 5 7 9 11 13]
沿轴1(列)求最和: [10 35]
整体求和: 45
- 均值函数
np.mean()
、标准差函数np.std()
(PyTorch中的torch.mean()
、torch.std()
必须传入浮点型张量)
arr = np.arange(10).reshape(2, 5)
print(arr)
print("沿轴0(行)求平均:", np.mean(arr, axis=0))
print("沿轴1(列)求平均:", np.mean(arr, axis=1))
print("整体求平均:", np.mean(arr))
[[0 1 2 3 4]
[5 6 7 8 9]]
沿轴0(行)求平均: [2.5 3.5 4.5 5.5 6.5]
沿轴1(列)求平均: [2. 7.]
整体求平均: 4.5
以上聚合函数存在安全版本,计算时忽略缺失值:np.nansum()
、np.nanprod()
、np.nanmean()
、np.nanstd()
、np.nanmax()
、np.nanmin()
。
5 数组高级应用
5.1 条件操作与布尔掩码
5.1.1 创建布尔型数组
布尔型数组可通过其他数组进行关系运算产生,关系运算符包括:<
、<=
、>
、>=
、==
、!=
。
# 数组与数字作比较
arr = np.arange(1, 7).reshape(2, 3)
print(arr, '\n')
print(arr >= 4)
[[1 2 3]
[4 5 6]]
[[False False False]
[ True True True]]
# 同维度数组作比较
arr1 = np.arange(1, 5)
arr2 = np.flipud(arr1)
print(arr1)
print(arr2)
print(arr1 > arr2)
[1 2 3 4]
[4 3 2 1]
[False False True True]
可以同时比较多个条件,但Python中的与and
、或or
、非not
关键字在NumPy中分别对应于与&
、或|
、非~
,且每项条件均需打上括号。
# 多个条件
arr = np.arange(1, 10)
print(arr)
print((arr < 4) | (arr > 6))
[1 2 3 4 5 6 7 8 9]
[ True True True False False False True True True]
5.1.2 处理True的数量
常需处理布尔型数组中True的数量,可使用以下函数
np.sum()
:统计布尔型数组中True的个数(直接求和)
arr = np.random.randn(10000)
print(arr)
print(np.sum(np.abs(arr) < 1)) # 条件等价于 (-1 < arr) & (arr < 1)
[-0.20387374 -0.56463038 -1.224334 ... -0.81761016 1.74757847
-0.28217824]
6738
np.any()
:只要布尔型数组中含有至少一个True,就返回True
arr1 = np.random.randint(0, 20, 10)
arr2 = np.flipud(arr1)
print(arr1)
print(arr2)
print(np.any(arr1 == arr2))
[ 9 18 3 0 0 4 11 7 11 10]
[10 11 7 11 4 0 0 3 18 9]
False
np.all()
:当布尔型数组中全为True时,才返回True
arr = np.random.normal(500, 70, 10000)
print(arr)
print(np.all(arr > 250))
[491.67160038 448.53708466 566.29683258 ... 464.74095895 451.2642996
422.67970926]
False
5.1.3 布尔索引
若一个普通数组和一个布尔型数组的维度相同,可以将布尔型数组作为普通数组的掩码,由此对普通数组中的元素实行布尔索引,进行筛选。
用法1:筛选出数组中大于、等于或小于某个数的元素
arr = np.arange(1, 13).reshape(3, 4)
print(arr, '\n')
print(arr > 4, '\n')
# 筛选出 arr > 4 的元素
print(arr[arr > 4])
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
[[False False False False]
[ True True True True]
[ True True True True]]
[ 5 6 7 8 9 10 11 12]
用法2:筛选出数组逐元素比较的结果
arr1 = np.arange(1, 10)
arr2 = np.flipud(arr1)
print(arr1)
print(arr2)
print(arr1 > arr2, '\n')
# 筛选出 arr1 > arr2 位置上的元素
print(arr1[arr1 > arr2])
print(arr2[arr1 > arr2])
[1 2 3 4 5 6 7 8 9]
[9 8 7 6 5 4 3 2 1]
[False False False False False True True True True]
[6 7 8 9]
[4 3 2 1]
5.1.4 按条件查找元素索引:np.where()
函数np.where()
用于获取满足某条件的所有元素所在的索引位置。该函数返回一个元组,其第1个元素即为存储了满足条件的元素所在位置的数组。
arr = np.random.normal(500, 70, 10000)
print(arr, '\n')
# 找出大于700的元素所在位置
print(np.where(arr > 700))
# 找出最大值元素所在位置
print(np.where(arr == np.max(arr)))
[462.81347684 596.2914063 656.38311222 ... 492.76311792 459.20664451
382.66449486]
(array([ 210, 1387, 3120, 3749, 3970, 4214, 4982, 5427, 5811, 6365, 7287,
7348, 7429, 7993, 8043, 8673, 9378, 9611, 9615, 9935]),)
(array([4214]),)
5.2 排序与索引:np.sort()、np.argsort()
使用函数np.sort()
对数组进行排序,返回排序后的数组;使用函数np.argsort()
返回排序后的索引。
arr = np.array([3, 1, 6, 2, 5, 4])
sorted_arr = np.sort(arr) # 对数组进行排序
sorted_indices = np.argsort(arr) # 获得排序后的索引
print("排序后的数组:", sorted_arr)
print("排序后的索引:", sorted_indices)
排序后的数组: [1 2 3 4 5 6]
排序后的索引: [1 3 0 5 4 2]
5.3 唯一值和重复值处理:np.unique()、np.repeat()
使用np.unique()
函数可以获取数组中的唯一值;使用np.repeat()
函数可以将数组中的元素重复,需再指定次数。
arr = np.array([1, 2, 2, 3, 3, 4, 4, 5])
unique_values = np.unique(arr)
repeated_arr = np.repeat(arr, 3) # 每个元素重复3次
print("唯一值:", unique_values)
print("重复后的数组:", repeated_arr)
唯一值: [1 2 3 4 5]
重复后的数组: [1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5]
6 文件输入输出
6.1 文本文件读取:np.loadtxt()
np.loadtxt()
函数可以从文本文件中加载数据到数组中,可指定数据划分符参数delimiter
。
loaded_arr = np.loadtxt("output.txt", delimiter=",")
print("从文件中加载的数组:\n", loaded_arr)
6.2 处理缺失值:np.genfromtxt()
np.genfromtxt()
函数可以处理包含缺失值的文本文件,可设置参数missing_Values
来指定何为缺失值,并设置填充参数filling_values
。
loaded_arr = np.genfromtxt(data, delimiter=",", missing_values="", filling_values=np.nan)
print("处理缺失值后的数组:\n", loaded_arr)
6.3 二进制文件输入输出:np.save()、np.load()
np.save()
和np.load()
函数可以分别保存和加载NumPy数组为二进制文件,保留数组的结构和数据类型。
arr = np.array([[1, 2, 3], [4, 5, 6]])
np.save("output.npy", arr)
loaded_arr = np.load("output.npy")
print("从文件中加载的数组:\n", loaded_arr)
7 其他
7.1 拼接:np.c_、np.r_
对象np.c_
、np.r_
分别可以按列(左右)、按行(上下)拼接数组
arr3 = np.c_[arr1, arr2] # 按列拼接arr1、arr2
arr4 = np.r_[arr1, arr2] # 按行拼接arr1、arr2
7.2 提取对角矩阵:np.diag()
函数np.diag()
构造、提取一个对角矩阵(对角线以外的元素全为0)。若传入1\times n
的向量,则直接以该向量元素为对角线元素,返回n\times n
的矩阵;若传入矩阵,则直接返回将其非对角线元素置0的矩阵。
L = np.diag([1, 2, 3, 4])