TOC
KINA

KINA-0

Start having fun with KINA right now!

NumPy数组库简介

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):等差数组创建,生成从startend上的num个数的等差数列。参考arange()函数。
  • np.logspace(start, end, num=50, base=10):等比数组创建,生成从start * baseend * 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])

发表评论