面向 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. NumPy 的优势在于可以访问 Python 库,包括: SciPy , Matplotlib , Pandas , OpenCV 等. 此外,Python 通常 embedded as a scripting language 在其他软件中,从而允许 NumPy 也在此处使用. |
MATLAB 数组切片使用按值传递语义,并采用延迟写入时复制方案,以防止在需要时才创建副本. 切片操作会复制数组的部分内容. |
NumPy 数组切片使用按引用传递,不会复制参数. 切片操作是数组的视图. |
大致等价#
下表给出了某些常见 MATLAB 表达式的大致等价形式. 这些是相似的表达式,不是等价的. 有关详细信息,请参见 documentation .
在下表中,假定您已在 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)
|
使用 for 循环和 |
|
|
短路逻辑 AND 运算符( Python native operator );仅限标量参数 |
|
|
短路逻辑 OR 运算符( Python native operator );仅限标量参数 |
>> 4 == 4
ans = 1
>> 4 == 5
ans = 0
|
>>> 4 == 4
True
>>> 4 == 5
False
|
Python 中的 boolean objects 是 |
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 的 2D 数组 |
|
|
从块 |
|
|
访问 MATLAB 向量(1xn 或 nx1)或 1D NumPy 数组 |
|
|
访问 2D 数组 |
|
|
2D 数组 |
|
|
2D 数组 |
|
|
2D 数组 |
|
|
2D 数组 |
|
|
第 2,4 和 5 行以及第 1 和 3 列.这允许修改矩阵,并且不需要规则切片. |
|
|
|
|
|
|
|
|
行以相反顺序排列的 |
|
|
|
|
|
|
|
|
|
|
|
矩阵乘法 |
|
|
逐元素相乘 |
|
|
逐元素相除 |
|
|
逐元素求幂 |
|
|
矩阵的第i,j个元素是 (a_ij > 0.5). MATLAB 的结果是逻辑值 0 和 1 的数组. NumPy 的结果是布尔值 |
|
|
查找 ( |
|
|
提取向量 v > 0.5 时 |
|
|
提取列向量 v > 0.5 时 |
|
|
|
|
|
|
|
|
将所有值设置为相同的标量值 |
|
|
NumPy 按引用赋值 |
|
|
NumPy 切片按引用 |
|
|
将数组转换为向量(请注意,这会强制复制). 要获得与 MATLAB 中相同的数据排序,请使用 |
|
|
创建递增向量 (参见 RANGES ) |
|
|
创建递增向量 (参见 RANGES ) |
|
|
创建列向量 |
|
|
一个由 64 位浮点零组成的 3x4 二维数组 |
|
|
一个由 64 位浮点零组成的 3x4x5 三维数组 |
|
|
一个由 64 位浮点 1 组成的 3x4 二维数组 |
|
|
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 之间(包括 1 和 3)的 4 个等间距样本 |
|
|
两个 2D 数组:一个包含 x 值,另一个包含 y 值 |
|
在网格上评估函数的最佳方法 |
|
|
|
|
|
在网格上评估函数的最佳方法 |
|
|
|
创建 |
|
|
连接 |
|
|
连接 |
|
|
|
|
|
数组 |
|
|
数组 |
|
|
逐个元素比较 |
|
|
向量 |
|
|
逐元素 AND 运算符(NumPy ufunc) See note LOGICOPS |
|
|
逐元素 OR 运算符(NumPy ufunc) See note LOGICOPS |
|
|
按位 AND 运算符(Python 原生和 NumPy ufunc) |
|
|
按位 OR 运算符(Python 原生和 NumPy ufunc) |
|
|
方阵二维数组 |
|
|
二维数组 |
|
|
二维数组 |
|
如果 |
求解 a x = b 中的 x |
|
求解 |
求解 x a = b 中的 x |
|
|
|
|
|
二维数组的 Cholesky 分解 |
|
|
|
|
|
|
|
|
找到二维数组 |
|
|
QR 分解 |
|
|
带有部分旋转的 LU 分解 (注意: P(MATLAB) == transpose(P(NumPy))) |
|
|
共轭梯度求解器 |
|
|
|
|
|
|
|
|
对二维数组 |
|
|
对二维数组 |
|
|
将数组 |
|
|
执行 \(\mathbf{Zx}=\mathbf{y}\) 形式的线性回归 |
|
|
使用低通滤波进行降采样 |
|
|
数组 |
|
|
移除数组 |
注意#
子矩阵: 可以使用 ix_ 命令对子矩阵进行赋值.例如,对于二维数组 a ,可以执行以下操作: ind=[1, 3]; a[np.ix_(ind, ind)] += 100 .
帮助: 没有与 MATLAB 的 which 命令直接对应的命令,但是 help 命令通常会列出函数所在的文件名.Python 还有一个 inspect 模块(执行 import inspect ),它提供了一个 getfile ,通常可以使用.
索引: MATLAB 使用基于 1 的索引,因此序列的初始元素的索引为 1.Python 使用基于 0 的索引,因此序列的初始元素的索引为 0.由于每种方式都有其优点和缺点,因此会引起混乱和争论.基于 1 的索引与常用的人类语言用法一致,其中序列的"第一个"元素的索引为 1.基于 0 的索引 simplifies indexing .另请参见 a text by prof.dr. Edsger W. Dijkstra .
范围: 在 MATLAB 中, 0:5 既可以用作范围文字,也可以用作"切片"索引(在圆括号内);但是,在 Python 中,像 0:5 这样的构造只能用作切片索引(在方括号内).因此,创建了有点古怪的 r_ 对象,以使 NumPy 具有类似的简洁范围构造机制.请注意, r_ 不是像函数或构造函数那样被调用,而是使用方括号进行索引,这允许在参数中使用 Python 的切片语法.
逻辑运算: NumPy 中的 & 或 | 是按位与/或,而在 MATLAB 中,& 和 | 是逻辑与/或.两者看起来可能工作方式相同,但是存在重要的差异.如果您将使用 MATLAB 的 & 或 | 运算符,则应使用 NumPy 的 ufunc logical_and / logical_or .MATLAB 和 NumPy 的 & 和 | 运算符之间的显着区别是:
非逻辑 {0,1} 输入:NumPy 的输出是输入的按位与.MATLAB 将任何非零值视为 1,并返回逻辑与.例如,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 代码时,可能需要首先将矩阵重塑为线性序列,执行一些索引操作,然后再重塑回来.由于 reshape(通常)产生对同一存储的视图,因此应该可以相当有效地执行此操作.请注意,NumPy 中 reshape 使用的扫描顺序默认为"C"顺序,而 MATLAB 使用 Fortran 顺序.如果您只是转换为线性序列然后再转换回来,则这无关紧要.但是,如果您要转换依赖于扫描顺序的 MATLAB 代码中的 reshapes,则此 MATLAB 代码: z = reshape(x,3,4); 应该在 NumPy 中变为 z = x.reshape(3,4,order='F').copy() .
‘array’ 还是 ‘matrix’?我应该使用哪个?#
从历史上看,NumPy 提供了一种特殊的矩阵类型 np.matrix ,它是 ndarray 的一个子类,它使二元运算成为线性代数运算.您可能会在一些现有代码中看到它被用来代替 np.array .那么,应该使用哪一个呢?
简短回答#
使用数组.
它们支持 MATLAB 中支持的多维数组代数.
它们是 NumPy 的标准向量/矩阵/张量类型.许多 NumPy 函数返回数组,而不是矩阵.
元素级运算和线性代数运算之间有明显的区别.
如果您愿意,您可以拥有标准向量或行/列向量.
在 Python 3.5 之前,使用数组类型的唯一缺点是您必须使用 dot 而不是 * 来乘以(reduce)两个张量(标量积,矩阵向量乘法等).从 Python 3.5 开始,您可以使用矩阵乘法 @ 运算符.
鉴于以上情况,我们打算最终弃用 matrix .
详细回答#
NumPy 包含一个 array 类和一个 matrix 类. array 类旨在成为用于多种数值计算的通用 n 维数组,而 matrix 旨在专门促进线性代数计算. 实际上,两者之间只有少数关键差异.
运算符
*和@,函数dot()和multiply():对于
array,**表示元素级乘法,而 *@表示矩阵乘法;它们具有关联的函数multiply()和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:)逐元素乘法很容易:AB.:(你必须记住矩阵乘法有它自己的运算符,@.:)你可以将一维数组视为行向量或列向量.A @ v将v视为列向量,而v @ A将v视为行向量.这可以节省你输入大量转置的时间.:)array是 NumPy 的"默认"类型,因此它经过了最多的测试,并且是最有可能被使用 NumPy 的第三方代码返回的类型.:)非常适合处理任意维数的数据.:)如果你熟悉张量代数,那么在语义上更接近张量代数.:)所有操作(*,/,+,-等)都是逐元素的.:(来自scipy.sparse的稀疏矩阵与数组的交互效果不佳.
matrix:\\行为更像是 MATLAB 矩阵.<:(最大二维.要保存三维数据,你需要array或许 Python 的matrix列表.<:(最小二维.你不能有向量.它们必须被转换为单列或单行矩阵.<:(由于array是 NumPy 中的默认值,因此即使你给它们一个matrix作为参数,某些函数也可能返回一个array.NumPy 函数不应该发生这种情况(如果发生了,那就是一个 bug),但是基于 NumPy 的第三方代码可能不会像 NumPy 那样遵守类型保留.:)AB是矩阵乘法,因此它看起来就像你在线性代数中写的那样(对于 Python >= 3.5,普通数组使用@运算符也具有相同的便利性).<:(逐元素乘法需要调用函数multiply(A,B).<:(运算符重载的使用有点不合逻辑:*不起逐元素作用,但/起作用.与
scipy.sparse的交互更简洁.
因此,更建议使用 array .实际上,我们打算最终弃用 matrix .
自定义你的环境#
在 MATLAB 中,你可以用来自定义环境的主要工具是修改搜索路径,其中包含你喜欢的函数的位置.你可以将这些自定义设置放入启动脚本中,MATLAB 将在启动时运行该脚本.
NumPy,或者更确切地说,Python,也具有类似的功能.
要修改你的 Python 搜索路径以包括你自己的模块的位置,请定义
PYTHONPATH环境变量.要让特定的脚本文件在交互式 Python 解释器启动时执行,请定义
PYTHONSTARTUP环境变量以包含你的启动脚本的名称.
与 MATLAB 不同,在 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
链接#
另一个有些过时的 MATLAB/NumPy 交叉参考可以在 https://mathesaurus.sf.net/ 找到
可以在 topical software page 中找到大量用于 Python 科学工作的工具列表.
有关使用 Python 作为脚本语言的软件列表,请参阅 List of Python software: scripting
MATLAB® 和 SimuLink® 是 The MathWorks, Inc. 的注册商标.