面向 MATLAB 用户的 NumPy#
简介#
MATLAB® 和 NumPy 有很多共同点,但 NumPy 专用于与 Python 配合使用,它并不是 MATLAB 的克隆。本指南将帮助 MATLAB 用户开始使用 NumPy。
一些关键差异#
在 MATLAB 中,即使对于标量,基本类型也是多维数组。除非您指定维度数量和类型,否则 MATLAB 中的数组赋值会存储为双精度浮点数的 2D 数组。对这些数组的 2D 实例执行的操作仿照线性代数中的矩阵运算建模。 |
在 NumPy 中,基本类型是一个多维 |
MATLAB 从 1 开始对数字进行索引; |
NumPy(与 Python 一样)从 0 开始对数字进行索引; |
MATLAB 的脚本语言为线性代数创建,因此一些数组操作的语法比 NumPy 的更紧凑。另一方面,添加 GUI 和创建成熟应用程序的 API 更多或少是一个事后想法。 |
NumPy 以 Python 为基础,Python 是一种通用语言。NumPy 的优势在于可以访问 Python 库,包括: SciPy、Matplotlib、Pandas、OpenCV 等。此外,Python 通常 嵌入为其他软件中的脚本语言,这允许在其中使用 NumPy。 |
MATLAB 数组切片使用按值传递语义,使用延迟写时复制方案,以防止在需要之前创建副本。切片操作会复制数组的一部分。 |
NumPy 数组切片使用按引用传递,不会复制参数。切片操作是数组的视图。 |
近似当量#
下表给出了某些常见 MATLAB 表达式的近似当量。这些是类似表达式,而不是等价表达式。有关详细信息,请参阅 文档。
在下表中,假设您已在 Python 中执行了以下命令
import numpy as np
from scipy import io, integrate, linalg, signal
from scipy.sparse.linalg import cg, eigs
还假设,如果注释中提到“矩阵”,则参数是二维实体。
通用当量#
MATLAB |
NumPy |
注释 |
---|---|---|
|
|
获取有关函数 func 的帮助 |
|
找出定义 func 的位置 |
|
|
|
打印 func 的源(如果不是本机函数) |
|
|
使用文本 |
for i=1:3
fprintf('%i\n',i)
end
|
for i in range(1, 4):
print(i)
|
使用 |
|
|
短路逻辑 AND 运算符 (Python 本机运算符);仅适用于标量参数 |
|
|
短路逻辑 OR 运算符 (Python 本机运算符);仅适用于标量参数 |
>> 4 == 4
ans = 1
>> 4 == 5
ans = 0
|
>>> 4 == 4
True
>>> 4 == 5
False
|
Python 中的 布尔对象 是 |
a=4
if a==4
fprintf('a = 4\n')
elseif a==5
fprintf('a = 5\n')
end
|
a = 4
if a == 4:
print('a = 4')
elif a == 5:
print('a = 5')
|
创建一个 if-else 语句以检查 |
|
|
复数 |
|
|
双精度中从 1 到下一个可表示实数的距离 |
|
|
从保存到文件 |
|
|
使用 Runge-Kutta 4,5 对 ODE 进行积分 |
|
|
使用 BDF 方法对 ODE 进行积分 |
线性代数对等项#
MATLAB |
NumPy |
注释 |
---|---|---|
|
|
数组 |
|
|
数组元素数量 |
|
|
数组 |
|
|
获取数组 |
|
|
定义一个 2x3 的二维数组 |
|
|
从块 |
|
|
访问 MATLAB 向量(1xn 或 nx1)或 1D NumPy 数组 |
|
|
访问二维数组 |
|
|
二维数组 |
|
|
二维数组 |
|
|
二维数组 |
|
|
二维数组 |
|
|
第 2、4 和 5 行,第 1 和 3 列。这样可以修改矩阵,且不需要常规切片。 |
|
|
|
|
|
从第一行开始, |
|
|
按相反顺序排列的 |
|
|
首行副本附加到末尾的 |
|
|
转置 |
|
|
共轭转置 |
|
|
矩阵乘法 |
|
|
元素级乘法 |
|
|
元素级除法 |
|
|
元素级幂 |
|
|
i、jth 元素为 (a_ij > 0.5) 的矩阵。MATLAB 结果是一个由逻辑值 0 和 1 构成的数组。NumPy 结果是一个由布尔值 |
|
|
找到 ( |
|
|
提取向量 v > 0.5 的 |
|
|
提取列向量 v > 0.5 的 |
|
|
将小于 0.5 的 |
|
|
将小于 0.5 的 |
|
|
将所有值设置为相同标量值 |
|
|
NumPy 按引用赋值 |
|
|
NumPy 切片按引用执行 |
|
|
将数组转换为向量(请注意,这会强制进行复制)。要获得与 MATLAB 中相同的数据排序,请使用 |
|
|
创建不断增长的向量(请参阅注释 RANGES) |
|
|
创建不断增长的向量(请参阅注释 RANGES) |
|
|
创建列向量 |
|
|
3x4 满含 64 位浮点零的二维数组 |
|
|
3x4x5 满含 64 位浮点零的三维数组 |
|
|
3x4 满含 64 位浮点一的二维数组 |
|
|
3x3 单位矩阵 |
|
|
返回二维数组 |
|
|
返回一个方块对角矩阵,其非零值是向量 |
rng(42,'twister')
rand(3,4)
|
from numpy.random import default_rng
rng = default_rng(42)
rng.random((3, 4))
或较旧版本: |
生成默认随机数生成器和种子 = 42 的 3x4 随机数组 |
|
|
1 到 3 之间的 4 个相等间隔样本,包含 1 和 3 |
|
|
两个二维数组:一个为 x 值,另一个为 y 值 |
|
在网格上执行函数评估的最佳方式 |
|
|
|
|
|
在网格上执行函数评估的最佳方式 |
|
|
|
创建 |
|
|
连接 |
|
|
连接 |
|
|
|
|
|
数组 |
|
|
数组 |
|
|
按元素比较 |
|
|
向量 |
|
|
按元素执行 AND 运算(NumPy ufunc)参见注释 LOGICOPS |
|
|
按元素执行 OR 运算(NumPy ufunc)参见注释 LOGICOPS |
|
|
按位 AND 运算(Python 原生和 NumPy ufunc) |
|
|
按位 OR 运算(Python 原生和 NumPy ufunc) |
|
|
2D 数组 |
|
|
2D 数组 |
|
|
2D 数组 |
|
|
解关于 x 的 a x = b |
|
改为求解 |
解关于 x 的 x a = b |
|
|
|
|
|
二维数组的 Cholesky 分解 |
|
|
特征值 \(\lambda\) 和特征向量 \(v\),其中 \(\mathbf{a} v = \lambda v\) |
|
|
特征值 \(\lambda\) 和特征向量 \(v\),其中 \(\mathbf{a} v = \lambda \mathbf{b} v\) |
|
|
查找二维数组 |
|
|
QR 分解 |
|
|
带部分选转的 LU 分解(注意:P(MATLAB) == transpose(P(NumPy))) |
|
|
共轭梯度求解器 |
|
|
傅里叶变换 |
|
|
傅里叶逆变换 |
|
|
对 2D 数组 |
|
|
对 2D 数组 |
|
|
用数组 |
|
|
执行形式为 \(\mathbf{Zx}=\mathbf{y}\) 的线性回归 |
|
|
使用低通滤波进行降采样 |
|
|
数组 |
|
|
移除数组 |
说明#
子矩阵:可以使用 ix_
命令,使用索引列表对子矩阵进行赋值。例如,对于 2D 数组 a
,可以执行:ind=[1, 3]; a[np.ix_(ind, ind)] += 100
。
帮助:没有 MATALB which
命令的直接等效命令,但命令 help
通常会列出函数所在的文件名。Python 还具有 inspect
模块(执行 import inspect
),它提供一个通常可行的 getfile
。
索引:MATLAB 使用以一为基础的索引,所以序列的第一个元素有索引 1。Python 使用以零为基础的索引,所以序列的第一个元素有索引 0。这种差别引起了困惑和争论,因为每种方法都有各自的优点和缺点。以一为基础的索引与普通的人类语言用法一致,其中序列的“第一个”元素的索引为 1。以零为基础的索引 简化了索引。另请参阅 艾兹格·W·戴克斯特拉教授的文本。
范围:在 MATLAB 中,0:5
可以用作范围文本和“切片”索引(在括号内);然而,在 Python 中,0:5
等结构只能用作切片索引(在方括号内)。因此,创建了一个有点怪异的 r_
对象,允许 NumPy 具有一个简洁的范围构建机制。请注意,r_
不是像函数或构造函数那样调用,而是使用方括号进行索引,这允许在参数中使用 Python 的切片语法。
逻辑运算:NumPy 中的 &
或 |
是按位 AND/OR,而在 MATLAB 中&和 |
是逻辑 AND/OR。这两种方式表面上看是一样的,但有一些重要的区别。如果你使用的是 MATLAB 的 &
或 |
运算符,你应该使用 NumPy 的 ufunc logical_and
/logical_or
。MATLAB 的 &
和 |
运算符与 NumPy 中的同类运算符之间的显著区别是
非逻辑型 {0,1} 输入:NumPy 的输出是输入的按位 AND 操作。MATLAB 将任何非零值视为 1,并返回逻辑 AND 操作。例如,NumPy 中的
(3 & 4)
为0
,而 MATLAB 中的3
和4
都被视为逻辑真,而(3 & 4)
返回1
。优先级:NumPy 的 & 运算符比诸如
<
和>
等逻辑运算符优先级更高;MATLAB 则相反。
如果您知道自己有布尔型参数,那么可以使用 NumPy 的按位运算符,但要小心括号,如下所示:z = (x > 1) & (x < 2)
。NumPy 运算符没有 logical_and
和 logical_or
形式,这是 Python 设计的令人遗憾的后果。
RESHAPE 和线性索引:MATLAB 始终允许使用标量或线性索引访问多维数组,而 NumPy 则不行。线性索引在 MATLAB 程序中很常见,例如 find()
在矩阵中返回线性索引,而 NumPy 的 find 行为不同。在转换 MATLAB 代码时,可能需要首先将矩阵重构为线性序列,执行一些索引操作,然后重构回来。由于重构(通常)会创建指向同一存储空间的视图,因此可以非常高效地执行此操作。请注意,NumPy 中重构使用的扫描顺序默认为“C”顺序,而 MATLAB 使用 Fortran 顺序。如果只是转换为线性序列并返回,那么这并不重要。但是,如果您正在转换依赖扫描顺序的 MATLAB 代码中的重构,那么这种 MATLAB 代码:z = reshape(x,3,4);
在 NumPy 中应变为 z = x.reshape(3,4,order='F').copy()
。
“数组”还是“矩阵”?我应该使用哪一个?#
从历史上看,NumPy 已提供一种特殊的矩阵类型,np.matrix,它是 ndarray 的子类,它使二进制运算变为线性代数运算。您可能会看到一些现有代码中已将它用于 np.array。那么,应该用哪一个呢?
简短的回答#
使用数组.
它们支持 MATLAB 中支持的多维数组代数
它们是NumPy的标准向量/矩阵/张量类型。很多NumPy函数返回数组,而不是矩阵。
元素级操作和线性代数操作之间存在明显的区别。
若您愿意,可以使用标准向量或行/列向量。
在Python 3.5之前,使用数组类型唯一的缺点是您必须使用dot
,而不是*
来乘以(化简)两个张量(标量乘积、矩阵向量乘法等)。从Python 3.5开始,可以使用矩阵乘法@
运算符。
鉴于以上内容,我们最终打算弃用matrix
。
长答案#
NumPy同时包含array
类和matrix
类。array
类是一个通用n维数组,用于很多类型的数值计算,而matrix
则用于专门进行线性代数计算。实际上,两者只有少数几个关键差异。
运算符
*
和@
,函数dot()
和multiply()
对于
array
,``*``表示逐元素乘法,而``@``表示矩阵乘法;它们具有关联函数multiply()
和dot()
。(在Python 3.5之前,@
不存在,为了进行矩阵乘法必须使用dot()
)。对于
matrix
,``*``表示矩阵乘法,逐元素乘法必须使用multiply()
函数。
向量的处理(一维数组)
对于
array
,向量形状1xN、Nx1和N完全不同。诸如A[:,1]
的操作返回形状为N的一维数组,而不是形状为Nx1的二维数组。对一维array
进行转置没有任何效果。对于
matrix
,一维数组经常转换为 1xN 或 Nx1 矩阵(行或列向量)。A[:,1]
返回形状为 Nx1 的二维矩阵。
处理高维度数组(ndim > 2)
array
对象可以具有大于 2 的维度数;matrix
对象始终具有正好两个维度。
便利属性
array
有一个 .T 属性,它将返回数据的转置。matrix
也有 .H、.I 和 .A 属性,它们将分别返回共轭转置、求逆和矩阵的asarray()
。
便利构造函数
array
构造函数将(嵌套)Python 序列作为初始化器。例如,array([[1,2,3],[4,5,6]])
。matrix
构造函数此外还有一个便利的字符串初始化器。例如matrix("[1 2 3; 4 5 6]")
。
使用两者都有利有弊
array
:)
按元素乘法很容易:A*B
。:(
您必须记住,矩阵乘法有它自己的运算符@
。:)
您可以将一维数组视为行或列向量。A @ v
将v
视为列向量,而v @ A
将v
视为行向量。这可以帮您节省输入许多转置的麻烦。:)
array
是“默认的”NumPy 类型,所以它会获得最多的测试,并且最有可能由使用 NumPy 的第三方代码返回。:)
颇适合处理任意维度数的数据。:)
语义上更接近于张量代数(如果您熟悉这一领域的话)。:)
所有 操作(*
,/
,+
,-
等)都是逐个元素执行的。:(
来自scipy.sparse
的稀疏矩阵无法很好地与数组进行交互。
矩阵
:\\
行为更类似于 MATLAB 矩阵的行为。<:(
二维的最大值。若要保存三维数据,你需要array
,或者可能是matrix
的 Python 列表。<:(
二维的最小值。无法使用向量。必须将其转换为单列或单行矩阵。<:(
由于array
是 NumPy 中的默认值,即使你传入matrix
作为参数,某些函数也可能会返回array
。对于 NumPy 函数,这种情况不应该发生(如果发生,则为错误),但基于 NumPy 的第三方代码可能无法像 NumPy 那样遵守类型保留。:)
A*B
是矩阵乘法,因此它看起来就像你在线性代数中书写的那样(对于 Python >= 3.5,普通数组使用@
运算符也具有相同的功能)。<:(
逐元素乘法需要调用函数multiply(A,B)
。<:(
运算符重载的使用有点不合逻辑:*
不适用于逐元素运算,而/
适用于逐元素运算。与
scipy.sparse
的交互稍微简洁一点。
因此,强烈建议使用 array
。事实上,我们打算最终弃用 matrix
。
自定义你的环境#
在 MATLAB 中,你可以使用的主要工具是自定义搜索路径,其中包括你最喜欢的函数所在的位置。你可以将此类自定义项放入一个启动脚本中,MATLAB 会在启动时运行该脚本。
NumPy,或者更确切地说 Python,也具有类似的功能。
若要修改 Python 搜索路径,以包含您自己的模块的位置,请定义
PYTHONPATH
环境变量。若要启动交互式 Python 解释器时执行特定的脚本文件,请定义
PYTHONSTARTUP
环境变量,以包含您启动脚本的名称。
与 MATLAB 中路径上的任何内容都可立即调用的情况不同,在 Python 中,您需要先执行“import”语句,才能访问特定文件中 的函数。
例如,您可能会创建如下所示的启动脚本(注意:这仅是示例,不是“最佳实践”的陈述)
# Make all numpy available via shorter 'np' prefix
import numpy as np
#
# Make the SciPy linear algebra functions available as linalg.func()
# e.g. linalg.lu, linalg.eig (for general l*B@u==A@u solution)
from scipy import linalg
#
# Define a Hermitian function
def hermitian(A, **kwargs):
return np.conj(A,**kwargs).T
# Make a shortcut for hermitian:
# hermitian(A) --> H(A)
H = hermitian
若要使用已弃用的 matrix 和其他 matlib 函数
# Make all matlib functions accessible at the top level via M.func()
import numpy.matlib as M
# Make some matlib functions accessible directly at the top level via, e.g. rand(3,3)
from numpy.matlib import matrix,rand,zeros,ones,empty,eye
链接#
可以在 http://mathesaurus.sf.net/ 找到另一个较为过时的 MATLAB/NumPy 交叉引用。
可在 主题软件页面 中找到适用于 Python 的科学工作的工具的详尽列表。
请参阅 Python 软件列表:脚本,了解使用 Python 作为脚本语言的软件列表
MATLAB®和SimuLink®是The MathWorks, Inc.的注册商标。