适用于 MATLAB 用户的 NumPy#
简介#
MATLAB® 和 NumPy 有很多共同点,但 NumPy 是为与 Python 协作而创建的,而不是 MATLAB 的克隆。本指南将帮助 MATLAB 用户开始使用 NumPy。
一些主要区别#
在 MATLAB 中,基本类型(即使是标量)也是多维数组。MATLAB 中的数组赋值通常存储为双精度浮点数的二维数组,除非您指定维度数量和类型。对这些数组的二维实例的操作是基于线性代数中的矩阵操作进行建模的。 |
在 NumPy 中,基本类型是多维 |
MATLAB 的索引从 1 开始; |
NumPy 和 Python 一样,索引从 0 开始; |
MATLAB 的脚本语言是为线性代数而创建的,因此某些数组操作的语法比 NumPy 更紧凑。另一方面,用于添加 GUI 和创建完整应用程序的 API 或多或少是后来才考虑的。 |
NumPy 基于 Python,这是一种通用语言。NumPy 的优势在于可以访问包括 SciPy、Matplotlib、Pandas、OpenCV 等在内的 Python 库。此外,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)
|
使用 for 循环和 |
|
|
短路逻辑 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)或一维 NumPy 数组 |
|
|
访问二维数组 |
|
|
二维数组 |
|
|
二维数组 |
|
|
二维数组 |
|
|
二维数组 |
|
|
第 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))
或旧版本: |
使用默认随机数生成器和 seed = 42 生成一个 3x4 随机数组 |
|
|
1 到 3 之间(含 1 和 3)的 4 个等间隔样本 |
|
|
两个二维数组:一个用于 x 值,另一个用于 y 值 |
|
在网格上评估函数的最佳方式 |
|
|
|
|
|
在网格上评估函数的最佳方式 |
|
|
|
创建 |
|
|
连接 |
|
|
连接 |
|
|
|
|
|
数组 |
|
|
数组 |
|
|
逐元素比较 |
|
|
向量 |
|
|
逐元素 AND 运算符(NumPy ufunc) 参见注释 LOGICOPS |
|
|
逐元素 OR 运算符(NumPy ufunc) 参见注释 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 的索引简化了索引操作。另请参阅 Edsger W. Dijkstra 教授的一篇文章。
范围:在 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 代码时,可能需要先将矩阵重塑为线性序列,执行一些索引操作,然后再重塑回去。由于 reshape(通常)会生成相同存储的视图,因此应该可以相当高效地完成此操作。请注意,NumPy 中 reshape 使用的扫描顺序默认为“C”顺序,而 MATLAB 使用的 Fortran 顺序。如果您只是将其转换为线性序列并再转换回来,则无关紧要。但是,如果您正在转换依赖于扫描顺序的 MATLAB 代码中的 reshape,那么 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
而不是 *
来乘以(缩减)两个张量(点积、矩阵向量乘法等)。从 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
:)
元素级乘法很简单:A*B
。:(
您必须记住矩阵乘法有其自己的运算符@
。:)
您可以将一维数组视为行向量或列向量。A @ v
将v
视为列向量,而v @ A
将v
视为行向量。这可以省去您输入大量转置操作。:)
array
是 NumPy 的“默认”类型,因此它得到了最多的测试,并且是使用 NumPy 的第三方代码最有可能返回的类型。:)
擅长处理任何维数的数据。:)
如果您熟悉张量代数,它在语义上更接近张量代数。:)
所有操作(*
,/
,+
,-
等)都是元素级的。:(
scipy.sparse
中的稀疏矩阵与数组的交互性不佳。
matrix
:\\
行为更像 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 不同,在 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/ 找到
可以在主题软件页面找到使用 Python 进行科学工作的大量工具列表。
请参阅Python 软件列表:脚本,以获取使用 Python 作为脚本语言的软件列表
MATLAB® 和 SimuLink® 是 The MathWorks, Inc. 的注册商标。