Matlab用户使用NumPy

介绍

MATLAB®和 NumPy/SciPy 有很多共同之处。但是也有很多不同之处。创建NumPy和 SciPy是为了用Python最自然的方式进行数值和科学计算,而不是 MATLAB® 的克隆版。 本章节旨在收集有关两者的差异,主要是为了帮助熟练的MATLAB®用户成为熟练的NumPy和SciPy用户。

一些关键的差异

MATLAB numpy
在MATLAB®中,基本数据类型是双精度浮点数的多维数组。大多数表达式都接受这样的数组并返回这样的数组。 这些数组的二维实例上的操作设计得有些类似于线性代数中的矩阵运算。 在NumPy中,基本类型是多维 array. 在所有维度(包括2D)上对这些数组的操作都是元素级的操作。 但是,有一种特殊的矩阵类型用于做线性代数,它只是array类的一个子类。矩阵类数组的运算是线性代数运算
MATLAB使用基于1的索引。使用 1 下标作为元素的初始位置 :ref:` 参考 <numpy-for-matlab-users.notes>` Python使用基于0的索引。序列的初始元素使用 0 来查找。
MATLAB的脚本语言是为做线性代数而创建的。基本矩阵操作的语法很好, 但是用于添加GUI和制作成熟应用程序的API或多或少是事后才想到的。 NumPy基于Python, 它从一开始就被设计为一种优秀的通用编程语言。 虽然Matlab的一些数组操作的语法比NumPy更紧凑,但NumPy可以做许多Matlab所不能做的事情
在 MATLAB® 中,数组具有按值传递的语义,并有一个惰性写拷贝方案。 以防止在实际需要副本之前实际创建副本,切片操作复制数组的部分。 在NumPy数组,数组只是内存中的引用而已。 切片只是操作数组的视图层面而已。

arraymatrix 该用哪个

除了 np.ndarray 之外,NumPy还提供了一种额外的 matrix 类型,可以在一些现有代码中看到这种类型。 该用哪一个呢?

简要的回答

使用 arrays.

  • 它们是numpy的标准向量/矩阵/张量类型。许多numpy函数返回的是数组,而不是矩阵。
  • 元素级运算和线性代数运算之间有着明确的区别。
  • 如果你愿意,可以使用标准向量或行/列向量。

直到Python3.5,使用数组类型的唯一缺点是您必须使用 dot 而不是 * 来将两个张量 (标量乘积、矩阵向量乘法等)相乘(减少)。从 Python3.5 之后,您就可以使用矩阵乘法 @ 运算符。

鉴于以上所述,我们最终打算放弃 matrix

详细的回答

NumPy包含 array 类和 matrix 类。 array 类旨在成为用于多种数值计算的通用n维数组, 而 matrix 类则专门用于促进线性代数计算。实际上,两者之间只有少数几个关键区别。

  • 操作符 *@ ,函数 dot() , 和 multiply() :
    • 对于 array* 表示逐元素乘法,而``@‘是指矩阵乘法。它们有相关联的函数
      multiply()dot() 。在python3.5之前,@ 并不存在,因此必须使用 dot() 进行矩阵乘法
    • 对于 matrix* 是指矩阵乘法,而对于按元素计算的乘法,则必须使用 multiply() 函数。
  • 向量处理(一维数组)
    • 对于数组,向量形状1xN,Nx1和N都是不同的东西。像 A[:,1] 这样的操作返回形状N的一维数组, 而不是形状Nx1的二维数组。一维数组上的转置不起任何作用。
    • 对于矩阵,一维数组总是向上转换为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 @ vv 视为列向量, v @ Av 视为行向量. 这可以让你少传入许多的转置。
    • :) array 是默认的NumPy类型, 因此它获得的支持最多,并且大量的NumPy的 第三方包都使用了这个类型。
    • :) 它可以更稳定的处理任意数量级的数据。
    • :) 如果您熟悉张量代数,则在语义上更接近张量代数。
    • :) 所有的运算符 (*, /, +, - etc.) 都是元素级别的。
    • :( 稀疏矩阵 scipy.sparse 不与数组交互
  • matrix
    • :\\ 行为更像MATLAB®矩阵。
    • <:( 它的维度最大为二维,如果你想保存三维数据,你需要 array 或者一个 matrix 列表。.
    • <:( 它的维度最少也是二维,你不能有向量还必须将它们转换为单列或单行矩阵。
    • <:( 由于 array 类型是NumPy中的默认类型,因此即使你将 matrix 作为参数传入, 某些函数也可能返回一个 array类型。在NumPy的内部函数中应该没有出现可以接受矩阵作为参数的情况 (如果有,那它可能是一个bug),但基于NumPy的第三方包可能不像NumPy那样遵守类型规则。
    • :) A*B 是矩阵乘法,因此线性代数更方便(对于Python >= 3.5 的版本,普通数组与 @ 运算符具有同样的方便性
    • <:( ( 元素级乘法要求调用乘法函数: multiply(A,B)
    • <:( 操作符重载的使用有点不合逻辑:元素级别中 * 运算符并不会生效, 但是 / 运算符却可以。
    • scipy.sparse 的交互更简洁一些。

因此,使用 array 更可取。事实上,我们打算最终放弃 matrix

MATLAB和NumPy粗略的功能对应表

下表给出了一些常见 MATLAB® 表达式的粗略等价物。这些不是完全等价的, 而是应该被看作是引导你走向正确方向的暗示。有关详细信息,请参阅NumPy函数的内置文档。

在下表中,假设您已经在Python中执行了以下命令

from numpy import *
import scipy.linalg

如果下表中的 注释` `这一列的内容是和 ``matrix 有关的话,那么参数一定是二维的形式

一般功能的对应表

MATLAB numpy 注释
help func info(func) or help(func) or func? (in Ipython) 获得函数func的帮助
which func see note HELP 找出func定义的位置
type func source(func) or func?? (in Ipython) 打印func的源代码(如果不是原生函数的话)
a && b a and b 短路逻辑 AND 运算符 (Python 原生运算符),仅限标量参数。
a || b a or b 短路逻辑 OR 运算符 (Python 原生运算符),仅限标量参数。
1*i, 1*j, 1i, 1j 1j 复数
eps np.spacing(1) 数字1和最近的浮点数之间的距离
ode45 scipy.integrate.solve_ivp(f) 将ODE与Runge-Kutta 4,5整合在一起。
ode15s scipy.integrate.solve_ivp(f, method='BDF') 用BDF方法整合ODE

线性代数函数对应表

MATLAB NumPy 注释
ndims(a) ndim(a) or a.ndim 获取数组的维数
numel(a) size(a) or a.size 获取数组的元素个数
size(a) shape(a) or a.shape 求矩阵的“大小”
size(a,n) a.shape[n-1] 获取数组 a 的n维元素数量
[ 1 2 3; 4 5 6 ] array([[1.,2.,3.], [4.,5.,6.]]) 一个 2x3 矩阵的字面量
[ a b; c d ] block([[a,b], [c,d]]) 从块 a, b, c, 和 d 构造矩阵
a(end) a[-1] 访问1xn矩阵``a``中的最后一个元素
a(2,5) a[1,4] 访问第二行,第五列中的元素
a(2,:) a[1] or a[1,:] 取得a数组第二个元素全部
a(1:5,:) a[0:5] or a[:5] or a[0:5,:] 取得a数组的前五行
a(end-4:end,:) a[-5:] 取得a数组的后五行
a(1:3,5:9) a[0:3][:,4:9] a数组的第1行到第3行和第5到第9列,这种方式只允许读取
a([2,4,5],[1,3]) a[ix_([1,3,4],[0,2])] 行2,4和5以及第1列和第3列。这允许修改矩阵,并且不需要常规切片方式。
a(3:2:21,:) a[ 2:21:2,:] a数组每隔一行,从第3行开始,一直到第21行
a(1:2:end,:) a[ ::2,:] a 数组从第一行开始,每隔一行
a(end:-1:1,:) or flipud(a) a[ ::-1,:] 反转a数组的顺序
a([1:end 1],:) a[r_[:len(a),0]] 将a数组的第一行的副本添加到数组末尾
a.' a.transpose() or a.T a数组的转置
a' a.conj().transpose() or a.conj().T a数组的共轭转置
a * b a @ b 矩阵乘法
a .* b a * b 元素相乘
a./b a/b 元素相除
a.^3 a**3 元素幂运算
(a>0.5) (a>0.5) 其i, th元素为(a_ij > 0.5)的矩阵。Matlab的结果是一个0和1的数组。 NumPy结果是一个布尔值False和True的数组
find(a>0.5) nonzero(a>0.5) 找到条件满足 (a > 0.5) 的索引
a(:,find(v>0.5)) a[:,nonzero(v>0.5)[0]] 找到满足条件 向量v > 0.5 的列
a(:,find(v>0.5)) a[:,v.T>0.5] 找到满足条件 列向量v > 0.5 的列
a(a<0.5)=0 a[a<0.5]=0 元素小于0.5 赋为 0
a .* (a>0.5) a * (a>0.5) a乘上a中大于0.5的值的矩阵
a(:) = 3 a[:] = 3 将所有值设置为相同的标量值
y=x y = x.copy() numpy 通过拷贝引用来赋值
y=x(2,:) y = x[1,:].copy() numpy 通过拷贝引用来切片操作
y=x(:) y = x.flatten() 将数组转换为向量(请注意,这将强制拷贝)
1:10 arange(1.,11.) or r_[1.:11.] or r_[1:10:10j] 创建一个可增长的向量 (参见下面的 注释)
0:9 arange(10.) or r_[:10.] or r_[:9:10j] 创建一个可增长的向量 (参见下面的 注释)
[1:10]' arange(1.,11.)[:, newaxis] 创建一个列向量
zeros(3,4) zeros((3,4)) 创建一个全是0的填充的 3x4 的64位浮点类型的二维数组
zeros(3,4,5) zeros((3,4,5)) 创建一个全是0的填充的 3x4x5 的64位浮点类型的三维数组
ones(3,4) ones((3,4)) 创建一个全是 1 的填充的 3x4 的64位浮点类型的二维数组
eye(3) eye(3) 创建一个3x3恒等矩阵
diag(a) diag(a) 创建a数组的对角元素向量
diag(a,0) diag(a,0) 创建方形对角矩阵,其非零值是a的所有元素 a
rand(3,4) random.rand(3,4) 创建一个随机的 3x4 矩阵
linspace(1,3,4) linspace(1,3,4) 创建4个等间距的样本,介于1和3之间
[x,y]=meshgrid(0:8,0:5) mgrid[0:9.,0:6.] or meshgrid(r_[0:9.],r_[0:6.] 两个2维数组:一个是x值,另一个是y值
  ogrid[0:9.,0:6.] or ix_(r_[0:9.],r_[0:6.] 最好的方法是在一个网格上执行函数
[x,y]=meshgrid([1,2,4],[2,4,5]) meshgrid([1,2,4],[2,4,5])  
  ix_([1,2,4],[2,4,5]) 最好的方法是在网格上执行函数
repmat(a, m, n) tile(a, (m, n)) 通过n份a的拷贝创建m
[a b] concatenate((a,b),1) or hstack((a,b)) or column_stack((a,b)) or c_[a,b] 连接a和b的列
[a; b] concatenate((a,b)) or vstack((a,b)) or r_[a,b] 连接a和b的行
max(max(a)) a.max() 取a数组的中的最大元素(对于matlab来说,ndims(a) <= 2)
max(a) a.max(0) 求各列的最大值
max(a,[],2) a.max(1) 求各行最大值
max(a,b) maximum(a, b) 比较a和b元素,并返回每对中的最大值
norm(v) sqrt(v @ v) or np.linalg.norm(v) 向量v的L2范数
a & b logical_and(a,b) 逐元素使用 AND 运算符 (NumPy ufunc) 参见注释
a | b logical_or(a,b) 逐元素使用 OR 运算符 (NumPy ufunc) 参见注释
bitand(a,b) a & b 按位AND运算符 (Python原生 和 NumPy ufunc)
bitor(a,b) a | b 按位 OR 运算符 (Python原生 和 NumPy ufunc)
inv(a) linalg.inv(a) 矩阵a的逆运算
pinv(a) linalg.pinv(a) 矩阵a的反逆运算
rank(a) linalg.matrix_rank(a) 二维数组或者矩阵的矩阵rank
a\b linalg.solve(a,b) if a is square; linalg.lstsq(a,b) otherwise 对于x,x = b的解
b/a Solve a.T x.T = b.T instead 对于x,x a = b的解
[U,S,V]=svd(a) U, S, Vh = linalg.svd(a), V = Vh.T a数组的奇值分解
chol(a) linalg.cholesky(a).T 矩阵的cholesky分解
[V,D]=eig(a) D,V = linalg.eig(a) a数组的特征值和特征向量
[V,D]=eig(a,b) V,D = np.linalg.eig(a,b) a,b数组的特征值和特征向量
[V,D]=eigs(a,k)   找到a的k个最大特征值和特征向量
[Q,R,P]=qr(a,0) Q,R = scipy.linalg.qr(a) Q,R 的分解
[L,U,P]=lu(a) L,U = scipy.linalg.lu(a) or LU,P=scipy.linalg.lu_factor(a) LU 分解 (注意: P(Matlab) == transpose(P(numpy))
conjgrad scipy.sparse.linalg.cg 共轭渐变求解器
fft(a) fft(a) a数组的傅立叶变换
ifft(a) ifft(a) a的逆傅里叶变换
sort(a) sort(a) or a.sort() 对矩阵或者数组进行排序
[b,I] = sortrows(a,i) I = argsort(a[:,i]), b=a[I,:] 对矩阵或数组的行进行排序
regress(y,X) linalg.lstsq(X,y) 多线性回归
decimate(x, q) scipy.signal.resample(x, len(x)/q) 采用低通滤波的下采样
unique(a) unique(a)  
squeeze(a) a.squeeze()  

Notes

子矩阵: 可以使用 ix_ 命令使用索引列表完成对子矩阵的分配. 例如, 对于2d阵列a, 有人可能会这样做: ind=[1,3]; a[np.ix_(ind,ind)]+=100.

帮助: 没有直接等同于MATLAB的 which 的命令,但是命令 helpsource 通常会列出函数所在的文件名。Python还提供了一个检 查模块(import inspect),该模块提供了一个经常被使用到的 getfile 方法。

索引: MATLAB® 使用基于1的索引,因此序列的初始元素具有索引1。 Python使用基于0的索引,因此数组的初始元素的索引为0。之所以有如此天壤之别, 是因为它们各有优缺点。使用基于1的索引是和常见的人类语言用法是一致的,前者是 序列的 第一个元素的索引是1。而后者基于0的索引简化了索引。

范围: 在 MATLAB® 中, 0:5 既可以用作范围文字索引,也可以用作片索引(括号内); 然而,在Python中,像 0:5 这样的结构只能用作片索引(方括号内)。因此,创建了有点奇怪的 r_ 对象,以允许numpy具有类似的简洁范围构造机制。请注意, r_ 不像函数或构造函数那样 被调用,而是使用方括号进行索引,这允许在参数中使用Python的切片语法。

逻辑运算: & 或者 | 在NumPy中是按位的 AND/OR,而在Matlab中 &| 是逻辑 AND/OR。对于任何有丰富编程经验的人来说,这一区别应该是显而易见的。这两种方法表面上看 起来是一样的,但也有重要的区别。如果您要使用Matlab的 &| 操作符,则应该使用NumPy函数的 logicaland/logicalor。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 )与线性(LINEAR)索引: Matlab总是允许使用标量或线性索引访问多维数组,而NumPy则不然。 线性索引在Matlab程序中很常见,例如:矩阵上的find()函数就会返回这在类型,而NumPy的查找行为 则不同。 在转换Matlab代码时可能需要首先将矩阵重塑为线性序列,执行一些索引操作然后再重塑。由 于重塑(通常)会在同一存储上生成视图,因此应该可以相当有效地执行此操作。 请注意,在NumPy中重 塑使用的扫描顺序默认为’C’顺序,而Matlab使用Fortran顺序。 如果您只是简单地转换为线性序列,那 么这无关紧要。但是如果要从依赖于扫描顺序的Matlab代码转换重构,那么这个Matlab代码:z = reshape(x, 3,4) 应该在NumPy中变成 z = x.reshape(3,4,order=’F’).copy() 。

自定义环境

在MATLAB®中,可用于自定义环境的主要工具是修改你喜欢的功能的位置的搜索路径(环境变量)。 您可以将这些自定义放入启动脚本中,MATLAB将在启动时运行该脚本。

NumPy,或者更确切地说是Python,具有类似的功能。

  • 要修改Python搜索路径以包含自己模块的位置,请定义 PYTHONPATH 的环境变量。
  • 要在启动交互式Python解释器时执行特定的脚本文件,请定义 PYTHONSTARTUP 环境变量以包含启动脚本的名称

与MATLAB®不同,可以立即调用路径上的任何内容,使用Python,您需要先执行 import 语句,以使特定文件中的函数可访问。

例如,您可能会创建一个类似于下面代码的启动脚本(注意:这只是一个示例,而不是“最佳做法”的声明)

# Make all numpy available via shorter 'num' prefix
import numpy as num
# 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 rand,zeros,ones,empty,eye
# Define a Hermitian function
def hermitian(A, **kwargs):
    return num.transpose(A,**kwargs).conj()
# Make some shortcuts for transpose,hermitian:
#    num.transpose(A) --> T(A)
#    hermitian(A) --> H(A)
T = num.transpose
H = hermitian

链接

有关另一个MATLAB®/ NumPy交叉引用, 请参见 http://mathesaurus.sf.net/

可以 主题软件页面 在. 中找到用于python科学工作的更多工具列表

MATLAB®和SimuLink®是The MathWorks的注册商标。