Python笔记 #2 NumPy

本文最后更新于:2023年10月31日 下午

学习 Machine Learning 的时候发现需要用许多矩阵运算和画图的库,本文将以实用主义的方式记录每次遇到的新用法。

2021 年贵系的暑培新增了「科学计算」内容,本文部分内容参考了清华 LZJ 同学的教程,部分参考自 NumPy 中文官网 参考手册。本文将持续更新。

常用的库

计算机领域,有用的数据特指结构化的数据,即符合一定的语法规范,才能方便计算机处理。这些数据包括表格型的数据,多维数组型的数据,由键位列关联起来的多张表数据等等。针对这些数据,Python 都有相应库去处理。

数据处理

  • NumPy:是 Numerical Python 的缩写,用于处理大规模多维数组矩阵计算等,有成熟的 C 接口,很多 Python 的第三方库都基于 NumPy 实现(例如 Python 的计算机视觉库 cv2 )。

  • Pandas:提供了更高级的数据结构和函数,适用于处理表格化结构化的数据。

科学计算

  • SciPy:Python 的科学计算库,可以处理积分微分、线性代数、最优化问题、信号处理、统计学等问题。
  • Scikit-learn:Python 的机器学习工具包,可以处理机器学习的众多计算问题,如支持向量机,聚类,特征选择等问题。
  • Statmodels:处理统计学和经济学问题的库,与 scikit-learn 相比包含更多经典模型。

数据可视化

  • Matplotlib:最经典的二维数据可视化库,结合 NumPy 使用可以成为 Matlab 的有力替代品。

自动化办公

  • docx:处理 Doc 文档。

  • pptx:处理 Powerpoint 幻灯片。

  • openpyxl:处理 Excel 表格。

NumPy 基础

NumPy 底层是用 C 写的,所以可以很方便的操作内存,这点与 Python 的原生数据结构不同。因此,NumPy 在处理大型数据时速度更快,内存开销也更小(和原生 Python 相比)。

ndarray 对象

ndarray 是 NumPy 的核心数据结构,全称是 N-dimensional Array,N 维数组,一个快速、灵活的大型数据集容器,内部储存同一类型的数据。

ndarray 有两个重要属性,dtypeshape,分别表示元素的数据类型形状参数,此外还有 ndim (维数), size (元素个数), itemsize (每个元素字节数) 等属性。

  • arr.dtypenp.dtype(arr):返回 arr 的数据类型,常见类型如下:
类型描述
int16/uint16有符号和无符号 16 位整数
int32/uint32有符号和无符号 32 位整数
int64/uint64有符号和无符号 64 位整数
float32标准单精度浮点数,兼容 C 的 float
float64标准双精度浮点数,兼容 C 的 double
float128拓展精度浮点数
complex128基于 float64 的复数
bool布尔值,为 True 或 False
  • arr2 = arr1.astype(np.float64):改变原数据类型为目标类型。
  • arr.shapenp.shape(arr):返回 arr 的形状参数,通常赋值给变量 (m, n),不同的参数含义如下:
arrarr.shapearr.dtype含义
array(1)()int32单个整数
array(1.)()float64单个浮点数
array([1, 2])(2,)int32一维数组,2 个元素
array([[1],
[2]])
(2, 1)int32二维数组,2 行 1 列
array([[1, 2]])(1, 2)int32二维数组,1 行 2 列
array([[1, 2],
[3, 4]])
(2, 2)int32二维数组,2 行 2 列
array([[[1, 1],
[1, 1]],
[[1, 1],
[1, 1]]])
(2, 2, 2)int32三维数组
  • arr.shape[0]arr.shape[1]:返回 arr 的第 0 维、第 1 维的长度。
  • arr.size:返回元素个数,通常赋值给变量 m,用于生成等长的数组。
  • np.set_printoptions(formatter={'float': '{: 0.6f}'.format}):设置全局精度。

ndarray 构造

根据不同的需求,有各种构造 ndarray 的方法。

  • 已有容器转化数组

生成 ndarray 的基本函数是 np.array(),其参数可以是 list 、tuple 或另一个 ndarray,会自动识别类型。其函数接口如下:

1
2
3
4
5
6
7
8
"""
obj: 传入原数组
dtype: 指定数据类型,默认根据原数组推断为 int32 或 float64
copy: 是否拷贝(不共享内存)
order: 数组存储风格,C 按行优先,F 按列优先,K 自适应
ndmin: 最小维数
"""
np.array(object, dtype = None, copy = True, order = 'K', subok = False, ndmin = 0)

样例测试如下:

1
2
3
4
5
6
7
8
9
10
11
# list
arr1 = np.array([1, 2, 3]) # arr1.shape = (3,)
arr2 = np.array([[1, 2], [3, 4]]) # arr2.shape = (2, 2)
# tuple
arr3 = np.array((1, 2, 3)) # arr3.shape = (3,)
arr4 = np.array(((1, 2), (3, 4))) # arr4.shape = (2, 2)
# float
arr5 = np.array([1, 2, 3.14]) # arr5.dtype = float64
arr6 = np.array([1, 2, 3], dtype = np.float64)
# merge
arr7 = np.array([arr1, arr5]) # arr7.shape = (2, 3)
  • 生成已初始化数组

NumPy 自带初始化函数,用来生成默认数组,以下为样例:

1
2
3
arr1 = np.zeros((2, 3))		# 全 0.  数组,arr1.shape = (2, 3)
arr2 = np.ones(10) # 全 1. 数组,arr2.shape = (10,)
arr3 = np.empty((3, 4, 5)) # 未初始化数组,arr3.shape = (3, 4, 5)

需要注意的是,传入的实参为生成数组的 shape,必须用元组表示!且生成的数组默认类型都为 float64。

若要生成高维数组,除了用 np.array() 拼接两个低维数组,通常都是用 np.empty() 实现。

  • 基于范围生成数组

生成方式与 Matlab 类似,这里给出函数接口:

1
2
3
4
5
6
# 范围在 [start, stop) 之间,缺省其一则视为 [0, stop),步长为 step
np.arange(start=0, stop, step=1, dtype=int32)
# 生成等差数列,[start, stop] 之间,限定总数为 num,endpoint 表示是否包含 stop 端点
np.linspace(start, stop, num=50, endpoint=True)
# 生成等比数列,注意范围是 [base^start, base^stop] 之间,限定总数为 num
np.logspace(start, stop, num=50, endpoint=True, base=10.0)
  • 生成随机数组

常用的有三种方式,这里给出函数接口:

1
2
3
4
5
6
# 生成 0 到 1 之间的浮点数,参数为各个维度,注意不能传入元组!
np.random.rand(d0, d1, ..., dn)
# 生成 [low, high) 之间的整数,缺省其一则视为 [0, high),size 用元组表示
np.random.randint(low, high, size=None, dtype=int)
# 生成 均值为 0,方差为 1 的正态分布浮点数,参数为各个维度
np.random.randn(d0, d1, ..., dn)
  • 从外部文件导入

实践最常用的方式是从外部文件导入大量数据集,Numpy 自身的文件后缀为 .npy,专用于 ndarray 的读写:

1
2
np.save("array", arr)
arr_copy = np.load("array.npy")

此外,Numpy 还有对 .txt 类型文件的读写方法,这里列出样例:

1
2
3
4
5
# 导入 .txt 文件,每行作为数组的一行,分隔符为逗号,选中前 2 列
data = np.loadtxt('ex1data1.txt', delimiter=',', usecols=(0, 1))
x = data[:, 0] # 第 0 列作为自变量
y = data[:, 1] # 第 1 列作为因变量
m = y.size # 元素组数定义为 m

当 .txt 文件有空缺数据时,需要使用复杂度更高的函数:

1
2
# 导入有空缺的 .txt 文件,每行作为数组的一行,分隔符为逗号,选中前 2 列
data = np.genfromtxt('ex1data1.txt', delimiter=',', usecols=(0, 1))

导入其他格式文件或许需要用到其他辅助库:

1
2
3
4
5
6
7
import numpy as np
import scipy.io as scio
# 导入 .mat 文件需要用到 scipy.io 模块,这是一个二进制字典文件
data = scio.loadmat('ex6data1.mat')
X = data['X'] # 获取字典键 'X'
y = data['y'].flatten() # 获取字典键 'y',展开成一维
m = y.size

ndarray 索引

ndarray 容器的赋值主要用索引完成,其基本特性:浅拷贝,即多个对象共用一块内存。NumPy 官方解释是,NumPy 主要用于处理大量数据,所以不希望用缺省复制的方式,否则会引起各种内存问题。

索引语法和原生 Python 类似,用数字和冒号表示左闭右开范围:

1
2
3
4
5
6
7
# 索引 [5,8) 位
arr1 = np.arange(6) # 内存中 [0, 1, 2, 3, 4, 5]
arr2 = arr1[3:4]
# 缺省,索引全部值
arr2[:] = 6 # 内存中 [0, 1, 2, 6, 6, 5]
# 如果不想索引原数组
arr3 = arr1[1:2].copy() # 用 .copy() 可以强制拷贝

对于高维数组,如果想通过赋值实现降维,可以使用切片索引

1
2
3
4
5
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr1[1][0], arr1[1, 0]) # 4 4,前者为 Python 列表索引
print(arr1[:1, 0:]) # [[1 2 3]]
print(arr1[:, 0]) # [1 4]
print(arr1[:, :1]) # [[1] [4]]

由第一个例子注意到,不同于原生 Python,高维数组还可以通过 [x,y,z] 的方式在不同维度之间索引,同时还可以用冒号加数字表示左闭右开范围。

特别注意最后两个例子,在第二维上虽然范围都是 0,但前者只用了数字,后者还用了冒号,导致结果的维数并不相同。这说明:使用冒号不会降维,哪怕确实范围中只有一列。

此外,NumPy 中还有一种布尔索引的有趣用法,不是本文重点,这里举个例子:

1
2
3
4
5
6
# 按 50% 概率,随机抽取序列
arr = np.arange(10) # 生成 待抽取 的序列 0 - 9
p = np.random.rand(10) # 生成 0 - 1 之间的随机小数
print(arr[p < 0.5]) # 利用标量语法,转化为 bool 数组,再索引 arr
# 浓缩成一行
print(np.arange(10)[np.random.rand(10) < 0.5])

ndarray 变形

ndarray 可通过一些自带的函数改变形状(维度),以便完成一些复杂的矩阵运算。

  • arr.flatten():返回一份深拷贝的展开成一维的数组,默认按行优先展开 order='C',用于矩阵时默认展开到 (n,1)
  • arr[:,np.newaxis]:将一维 arr 增加到二维数组 (m,1)。常用于生成列向量,才能点乘系数矩阵。
  • arr[np.newaxis,:]:将一维 arr 增加到二维数组 (1,m)
  • np.c_[arr1, arr2]:将二维数组按列相连,要求行数一致。如果对象是一维数组,视作 (m,1) 的二维数组。
    • np.column_stack([arr1, arr2]):类似 np.c_ 的函数形式,要求传入数组列表
    • np.hstack([arr1,arr2]):类似 np.c_ 的函数形式,要求传入数组列表
  • np.r_[arr1, arr2]:将二维数组按行相连,要求列数一致。如果对象是一维数组或常数,则仍拼成一维数组。
    • np.row_stack([arr1, arr2]):类似 np.r_ 的函数形式,要求传入数组列表
    • np.vstack([arr1,arr2]):类似 np.c_ 的函数形式,要求传入数组列表
  • np.reshape(arr, (5,5)):调整形状,默认按行展开后填到新形状,要求规模匹配。如果形状元组里某一维填 -1,则会根据其他维度计算该维长度。如果只有一个 -1,则效果同 arr.flatten()
  • np.flip(arr, axis=0):将 arr 在按行切片,并把次序颠倒。如果不加 axis 则会在所有维度都进行颠倒,常用于卷积核的翻转。
  • np.concatenate((a1,a2,...), axis=0):高效地拼接大规模数组,axis 表示拼接时切片的维度,对于一维数组默认拼完还是一维。
  • np.pad(arr, width, mode=‘edge’):在 arr 的每个轴边缘填充,填充的长度 width 为嵌套元组 ((before_1, after_1), ..., (before_N, after_N))mode 为填充的值,可以为边缘值、最大值、平均值等。

常用数学函数

ndarray 的另一特点是支持类标量语法的计算,标量会作用在数组的每一个元素上,例如:arr + 2arr * 10arr[:] = 2arr > 5 等。此外,还支持一系列运算函数,以下所有函数同样支持 数组变量.函数名(参数) 形式调用:

普通运算

  • np.sum(arr[1,:]):对一维数组 arr[1,:],求和,得到一个值。
  • np.sum(arr, 0):对二维数组 arr,求每一列和,塌缩(列数,)
  • np.sum(arr, 1):对二维数组 arr,求每一行和,塌缩成 (行数,)
  • np.max(arr):对整个数组,求最大值,得到一个值。
  • np.max(arr, 0):对二维数组 arr,求每一列最大值,塌缩成 (列数,)
  • np.argmax(arr,0):对二维数组 arr,求每一列最大值的索引,塌缩成 (列数,)
  • np.sin(arr)np.cos(arr)np.tan(arr):作用于每个元素求三角函数。
  • np.arcsin(arr)np.arccos(arr)np.arctan(arr):作用于每个元素求反三角函数。
  • np.arctan2(y, x)(x, y) 为坐标系上的一点,该函数可求出该点与原点连线到 x 轴的夹角,范围为 [-pi, pi],通常使用 np.arctan2(y, x) * 180 / np.pi 来求出夹角。
  • np.power(arr, n):作用于每个元素求 n 次幂。
  • np.square(arr):作用于每个元素求平方,更快。
  • np.sqrt(arr):作用于每个元素开根号,更快。

矩阵运算

  • arr1 @ arr2矩阵点乘,要求第一个矩阵的列数等于第二个矩阵的行数,一维数组视作二维数组的行向量或列向量

    • np.dot(arr1, arr2):同上,矩阵点乘
    • np.matmul(arr1, arr2):同上,矩阵点乘,支持高维矩阵的 Broadcast。
  • arr1 * arr2对应位置相乘,即 Hadmard 积,要求两个矩阵各个维度长度相等

    • np.multiply(arr1, arr2):同上,对应位置相乘。
  • arr1.T:求数组转置,数组没有求逆、共轭的函数。

  • np.transpose(arr1):同上,不指定参数时求二维数组的转置,高维数组需用元组指定索引,表示相应的索引顺序交换

线性代数

  • np.linalg.inv(arr):求逆矩阵,要求二维数组。
  • np.linalg.pinv(arr):求伪(广义)逆矩阵,要求二维数组。
  • np.linalg.det(arr):求行列式(标量),要求二维数组。
  • np.linalg.solve(A,b):解形如 Ax=b 线性方程组。
  • w = np.linalg.eigvals(arr):求矩阵特征值,w 为 (m,) 一维数组,存放特征值。
  • w,v = np.linalg.eig(arr):求矩阵特征值,v 为 (m,m) 二维数组,每一列都是特征向量,与 w 对应。
  • np.linalg.svd(arr):求矩阵的 SVD 分解,arr 为 (m,n) 二维数组,三个返回值:U 为 (m,m),Sigma 为(m,n),VT 为 (n,n)。
  • np.linalg.norm(arr, axis=0, ord=1):按列求向量 1 范数。
  • np.linalg.norm(arr, axis=0, ord=2):按列求向量 2 范数,默认选项。
  • np.linalg.norm(arr, axis=0, ord=np.inf):按列求向量无穷范数。

统计运算

  • np.mean(arr):求所有样本平均值。
  • np.mean(arr, 0):对二维数组 arr,求每一列样本平均值,塌缩(列数,)
  • np.average(arr, weights=None):求样本加权平均值。
  • np.std(arr):求所有样本标准差。
  • np.std(arr, ddof=1):求所有样本无偏标准差。
  • np.std(arr, axis=0, ddof=1):对二维数组 arr,求每一列样本无偏标准差,塌缩(列数,)
  • np.var(arr):求所有样本方差,相当于标准差的平方。
  • np.cov(arr):对一维数组 arr,相当于求自身的协方差(退化为无偏方差),即无偏标准差的平方。
  • np.cov(arr):对二维数组 arr,返回一个二维数组,元素 [i,j] 代表arr[i]arr[j] 两列元素的协方差。

NumPy 进阶

matrix 对象

除了 ndarray,NumPy 针对二维数组还专门设置了一个矩阵对象。matrix 的大部分性质与 ndarray 无异,但多了一些功能函数:

  • np.mat([[1,2],[5,7]]):声明矩阵,注意维数必须为 2。
  • np.mat([1,2,3]):会被强制转化为 (1,3) 的二维矩阵。
  • np.mat(arr1)np.asmatricx(arr1):从数组转到矩阵。
  • np.asarray(mat1):从矩阵转到数组。
  • mat1.Tmat1.Hmat1.I:求转置矩阵、共轭矩阵、逆矩阵。
  • mat1 * mat2点乘,要求第一个矩阵的列数等于第二个矩阵的行数。
  • np.multiply(mat1, mat2)对应位置相乘,要求两个矩阵各个维度长度相等

Broadcast 广播机制

NumPy 中对于两个 ndarray 的加减乘除都是标量操作,即对应位置元素之间的操作。并且,当两个数组的形状不同时,NumPy 自带的 Broadcast 机制会自动扩展数组进行操作,这是 NumPy 向量化运算的基石。

例如,在归一化变量时,我们使用:

1
2
# 元素减去平均值,除以无偏标准差
data = (data - data.mean(0)) / data.std(axis=0, ddof=1)

很明显,data 和塌缩后的 np.mean(data, 0) 形状不相同,但仍可以相减。

广播兼容的条件有两种:

  • 两个不同维度的数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符。如:(4,3)(3,)(5,6,7)(6,7)
  • 两个相同维度的数组,但其中在某一维度上仅为 1。如 (4,5,6)(4,1,6)(4,5,1)

爱因斯坦求和

爱因斯坦求和法 np.einsum() 函数是一个非常强大的工具,用于执行各种复杂张量运算,属于是矩阵乘法的泛化版。它可以在不创建中间数组的情况下,高效地执行多种线性代数、张量操作和张量缩并操作。参数如下:

1
numpy.einsum(subscripts, *operands)
  • subscripts:爱因斯坦求和约定字符串,用于指定操作的具体形式。
  • operands:输入张量或数组。

在爱因斯坦求和法中,我们约定:

  1. 如果一个字母在两个输入中都出现了,那么就执行逐分量的乘法;
  2. 如果输出中不包含一个字母,则在该维度上执行求和。

例如,当我们想实现一个内积操作时,可以简化为:

1
2
3
4
5
A = np.array([[1, 2], [3, 4]])
B = np.array([2, 3])

# C[i] = A[i, j] * B[j], np.dot(A, B) 或 A @ B 可以实现
C = np.einsum('ij,j->i', A, B)

对两个三维数组进行对应位置相乘

1
2
3
4
5
A = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
B = np.array([[[2, 2], [2, 2]], [[3, 3], [3, 3]]])

# A * B 可以实现
C = np.einsum('ijk,ijk->ijk', A, B)

执行张量缩并操作,例如计算矩阵的

1
2
3
4
A = np.array([[1, 2], [3, 4]])

# np.trace(A) 可以实现
result = np.einsum('ii', A)

在 Transformer 中,最复杂的运算操作是自注意力层,其中除了 softmax 之外的一切都可以使用 einsum 表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# b: batch
# n: sequence length
# d: embedding dimension
# h: number of heads
# k: dimension of each head
def multihead_attention(X, W_q, w k, W_v, W_o):
"""
X: [b, n, d] (input array)
W_q, W_k, W_v, W_o [h, d, k] (projection parameters)
Y: [b, n, d] (output array)
"""
Q = einsum("bnd,hdk->bhnk", X, W_q)
K = einsum("bnd,hdk->bhnk", X, W_k)
V = einsum("bnd,hdk->bhnk", X, W_v)
scores = einsum("bhnk,bhmk->bhnm", Q, K)
weights = softmax(scores)
O = einsum("bhnm,bhmk->bhnk", weights, V)
Y = einsum("bhnk,hdk->bnd", O, W_o)
return Y

C-API

NumPy 提供了一个 C-API,使用户能够扩展系统并快速访问数组对象,以便在其他例程中使用。真正理解 C-API 的最好方法是阅读源代码,这里仅列举部分神奇的用法。

  • np.argpartition(arr, n):高效地将数组中的所有元素分割,分割点为结果下标 n 的元素,左侧是较小数,右侧是较大数。注意仅返回分割后数组的索引,常用于检索算法中输出 Top N 结果:

    1
    2
    3
    4
    5
    6
    7
    >>> a = np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
    >>> print(np.argpartition(a, -5))
    [6 9 4 3 7 2 1 5 8 0] # 结果的索引
    >>> a[np.argpartition(a, -5)]
    array([0, 0, 3, 3, 4, 4, 4, 9, 6, 9]) # 真正的结果
    >>> a[np.argpartition(a, -5)[-5:]]
    array([4, 4, 9, 6, 9]) # Top 5
  • np.where(condition):找出满足条件 condition 元素的坐标,返回一个 tuple,每一项是一个一维 ndarray,分别对应符合条件元素的各维坐标。简单的条件用布尔索引也可替代,常用于绘制散点图:

    1
    2
    3
    4
    5
    pos = np.where(y == 1)[0]
    neg = np.where(y == 0)[0] # 返回 label 为 0 和 1 的样本点的索引

    plt.scatter(X[pos, 0], X[pos, 1], marker="o", c='c')
    plt.scatter(X[neg, 0], X[neg, 1], marker="x", c='r') # 绘制散点图
  • X, Y = np.meshgrid(x, y):生成格点矩阵xy 需是一维向量,输出的是一个 x * y 格点矩阵的每个点的横纵坐标,XY 是形状为 (x, y) 的二维矩阵。常用于绘制等高线图:

    1
    2
    3
    4
    5
    u = np.linspace(-1, 1, 50)
    v = np.linspace(-1, 1, 50)
    U, V = np.meshgrid(u, v) # 生成 50x50 网格点矩阵
    z = (map_feature(U.flatten(), V.flatten()) @ theta).reshape((50, 50)) # 计算等高线
    plt.contour(u, v, z, [0], colors='r') # 绘制轮廓图,取高度为 0 的点
  • np.concatenate((np.ravel(a), np.ravel(b))):扁平化参数,其中 ravel(a) 是将多维数组变成一维数组,concatenate((arr1, arr2, ...),axis=0) 是将一维数组首尾相接。有些 SciPy 中的科学计算方法(梯度下降)需要一次性将所有参数线性输入,就可以用到这个。

  • np.cumsum(arr, axis=None):对一维、二维等数组求前缀和,如果不加 axis 参数则默认按行展开为一维数组后求前缀和;如果为 0 ,按照行累加,为 axis=1,按照列累加。

    1
    2
    3
    >>> a = np.array([[1,2,3], [4,5,6]])
    >>> np.cumsum(a)
    array([ 1, 3, 6, 10, 15, 21]) # 展开成一维数组
  • np.argsort(arr):返回的是元素值从小到大排序后的索引,内置快排实现,如果要从大到小,只需将参数改为 -arr,或者在后面跟上 [::-1] 表示逆序。常用于求完特征值和特征向量后进行排序,提取主成分:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> a = np.array([3,1,2,1,3,5])
    >>> np.argsort(a)
    array([1, 3, 2, 0, 4, 5]) # 升序
    >>> np.argsort(-a)
    array([5, 4, 0, 2, 3, 1]) # 降序

    # PCA z
    w, v = np.linalg.eig(M)
    sorted_indices = np.argsort(-w)
    eigenvalues = w[sorted_indices[:k]]
    eigenvectors = v[:, sorted_indices[:k]].astype(np.float64).T
  • grid = np.indices((H, W)):返回一个给定 shape=(2,H,W)序号网格数组,其中 grid[0] 里的每个元素为该位置元素的序号,grid[1]序号,可以用于局部提取数组元素:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> x = np.arange(20).reshape((5,4))
    >>> grid = np.indices((2,3))
    # [[[0 0 0],
    # [1 1 1]],
    # [[0 1 2],
    # [0 1 2]]]
    >>> x[grid[0], grid[1]]
    # [[0 1 2]
    # [4 5 6]]
  • np.allclose(arr1, arr2):用于检查两个数组是否每个元素都相似,返回布尔值,默认在 1e-5 的相对误差范围内。

  • np.nonzero(arr):用于得到 N 维数组中非零元素的位置(数组索引),返回一个N 元元组,每一个元素都为一个一维数组,tuple[i][j] 代表第 j 个非零元素的第 i 维下标:

    1
    2
    3
    4
    5
    6
    7
    a =[[1,2,3],
    [0,2,0],
    [0,2,2]]
    >>> np.nonzero(a)
    # (array([0, 0, 0, 1, 2, 2], dtype=int64), array([0, 1, 2, 1, 1, 2], dtype=int64))
    >>> indices = np.stack(np.nonzero(a)).T
    # array([[0,0], [0,1], [0,2], [1,1], [2,1], [2,2]])
  • np.all()np.any():用于判断整个数组中的元素是否全部满足条件、是否存在满足条件。本质上是实现了与、或运算。具体使用如下:

    1
    2
    3
    4
    5
    6
    a = [1, 2, 3]
    b = [1, 2, 4]
    >>> (a == b).all()
    # False
    >>> (a == b).any()
    # True
  • np.convolve(arr1, arr2):对两个一维数组的卷积运算(模拟信号操作),其中 arr2 会先翻转再平移。此外还可以选择模式设置是否存在边际效应。注:该方法实现简易,没有用到 FFT 优化,速度较慢。

    1
    2
    >>> np.convolve([1, 2, 3], [4, 5, 6])
    # array([4, 13, 28, 27, 18])

Python笔记 #2 NumPy
https://hwcoder.top/Python-Note-2
作者
Wei He
发布于
2021年9月25日
许可协议