面向MATLAB用户的NumPy

介绍

MATLAB®和NumPy有很多共同点,但是NumPy的创建是为了与Python一起工作,而不是作为MATLAB的克隆。本指南将帮助MATLAB用户开始使用NumPy。

一些关键区别

在MATLAB中,基本类型(即使是标量)也是多维数组。MATLAB中的数组指定存储为双精度浮点数的2D数组,除非指定维数和类型。对这些阵列的二维实例的操作是线性代数中矩阵操作的模型。

在NumPy中,基本类型是多维的 array . NumPy中的数组分配通常存储为 n-dimensional arrays 具有按顺序容纳对象所需的最小类型,除非指定尺寸和类型的数目。NumPy逐元素执行操作,因此将2D数组与 * 不是矩阵乘法,而是元素对元素的乘法。(The) @ 运算符,从python3.5开始就可用,可以用于传统的矩阵乘法。)

MATLAB从1开始计算指数; a(1) 是第一个元素。 See note INDEXING

NumPy和Python一样,从0开始计算索引; a[0] 是第一个元素。

MATLAB的脚本语言是为线性代数创建的,因此一些数组操作的语法比NumPy的更简洁。另一方面,添加gui和创建完整应用程序的API或多或少是事后才想到的。

NumPy是基于Python的,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 eigs

另外,假设下面的注释是关于“矩阵”的,那么参数是二维实体。

通用等效物

MATLAB

NumPy

笔记

help func

info(func) 或 help(func) 或 func? (在伊皮顿)

获取有关函数的帮助 func

which func

see note HELP

找出哪里 func 定义

type func

np.source(func) 或 func?? (在伊皮顿)

的打印源 func (如果不是本机函数)

% comment

# comment

用文本注释一行代码 comment

for i=1:3
    fprintf('%i\n',i)
end
for i in range(1, 4):
   print(i)

使用for循环打印数字1、2和3 range

a && b

a and b

短路逻辑与运算符 (Python native operator );仅标量参数

a || b

a or b

短路逻辑或运算符 (Python native operator );仅标量参数

>> 4 == 4
ans = 1
>> 4 == 5
ans = 0
>>> 4 == 4
True
>>> 4 == 5
False

这个 boolean objects 在Python中 True 和 False ,而不是MATLAB的逻辑类型 1 和 0 .

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语句以检查 a 为4或5并打印结果

1*i, 1*j, 1i, 1j

1j

复数

eps

np.finfo(float).eps or np.spacing(1)

64位浮点运算中舍入引起的相对误差的上限。

load data.mat

io.loadmat('data.mat')

加载保存到文件中的MATLAB变量 data.mat . (注意:将数组保存到 data.mat 在MATLAB/Octave中,使用最新的二进制格式。 scipy.io.loadmat 将创建一个包含已保存数组和其他信息的字典。)

ode45

integrate.solve_ivp(f)

将ODE与Runge Kutta 4,5集成

ode15s

integrate.solve_ivp(f, method='BDF')

将ODE与BDF方法集成

线性代数等价

MATLAB

NumPy

笔记

ndims(a)

np.ndim(a) or a.ndim

数组维数 a

numel(a)

np.size(a) or a.size

数组元素数 a

size(a)

np.shape(a) or a.shape

数组的“大小” a

size(a,n)

a.shape[n-1]

获取数组第n维的元素数 a . (请注意,MATLAB使用基于1的索引,而Python使用基于0的索引,请参见注释) INDEXING )

[ 1 2 3; 4 5 6 ]

np.array([[1. ,2. ,3.], [4. ,5. ,6.]])

定义2x3 2D阵列

[ a b; c d ]

np.block([[a, b], [c, d]])

从块构造矩阵 a , b , c 和 d

a(end)

a[-1]

访问MATLAB向量(1xn或nx1)或1D NumPy数组中的最后一个元素 a (长度n)

a(2,5)

a[1, 4]

访问2D数组第二行第五列中的元素 a

a(2,:)

a[1] or a[1, :]

整个二维数组的第二行 a

a(1:5,:)

a[0:5] or a[:5] or a[0:5, :]

二维数组的前5行 a

a(end-4:end,:)

a[-5:]

2D数组的最后5行 a

a(1:3,5:9)

a[0:3, 4:9]

二维数组的第一到第三行和第五到第九列, a .

a([2,4,5],[1,3])

a[np.ix_([1, 3, 4], [0, 2])]

第2、4、5行和第1、3列。这样就可以修改矩阵,而不需要常规切片。

a(3:2:21,:)

a[2:21:2,:]

每隔一行 a 从第三个开始到第二十一个

a(1:2:end,:)

a[ ::2,:]

每隔一行 a ,从第一个开始

a(end:-1:1,:) or flipud(a)

a[::-1,:]

a 行的顺序相反

a([1:end 1],:)

a[np.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,jth元素为(a_ij>0.5)的矩阵。MATLAB结果是逻辑值0和1的数组。NumPy结果是一个布尔值数组 False 和 True .

find(a > 0.5)

np.nonzero(a > 0.5)

查找索引 (a > 0.5)

a(:,find(v > 0.5))

a[:,np.nonzero(v > 0.5)[0]]

提取…的柱状物 a 其中矢量v>0.5

a(:,find(v>0.5))

a[:, v.T > 0.5]

提取…的柱状物 a 其中,列向量v>0.5

a(a<0.5)=0

a[a < 0.5]=0

a 元素小于0.5归零

a .* (a>0.5)

a * (a > 0.5)

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()

将数组转换为向量(请注意,这会强制创建一个副本)。要获得与MATLAB中相同的数据顺序,请使用 x.flatten('F') .

1:10

np.arange(1., 11.) or np.r_[1.:11.] or np.r_[1:10:10j]

创建一个递增向量(参见注释 RANGES )

0:9

np.arange(10.) or np.r_[:10.] or np.r_[:9:10j]

创建一个递增向量(参见注释 RANGES )

[1:10]'

np.arange(1.,11.)[:, np.newaxis]

创建列向量

zeros(3,4)

np.zeros((3, 4))

3x4二维数组,包含64位浮点零

zeros(3,4,5)

np.zeros((3, 4, 5))

3x4x5三维数组,包含64位浮点零

ones(3,4)

np.ones((3, 4))

3x4二维数组,包含64位浮点型

eye(3)

np.eye(3)

3x3单位矩阵

diag(a)

np.diag(a)

返回2D数组对角线元素的向量, a

diag(v,0)

np.diag(v, 0)

返回一个非零值为向量元素的平方对角矩阵, v

rng(42,'twister')
rand(3,4)
from numpy.random import default_rng
rng = default_rng(42)
rng.random(3, 4)

或旧版本: random.rand((3, 4))

使用默认的随机数生成器和seed=42生成一个随机3x4数组

linspace(1,3,4)

np.linspace(1,3,4)

4个等距样品,介于1和3之间,包括

[x,y]=meshgrid(0:8,0:5)

np.mgrid[0:9.,0:6.] or np.meshgrid(r_[0:9.],r_[0:6.]

两个二维数组:一个是x值,另一个是y值

ogrid[0:9.,0:6.] or np.ix_(np.r_[0:9.],np.r_[0:6.]

在网格上评估函数的最佳方法

[x,y]=meshgrid([1,2,4],[2,4,5])

np.meshgrid([1,2,4],[2,4,5])

ix_([1,2,4],[2,4,5])

在网格上评估函数的最佳方法

repmat(a, m, n)

np.tile(a, (m, n))

创建m x n个副本 a

[a b]

np.concatenate((a,b),1) or np.hstack((a,b)) or np.column_stack((a,b)) or np.c_[a,b]

连接的列 a 和 b

[a; b]

np.concatenate((a,b)) or np.vstack((a,b)) or np.r_[a,b]

连接的行 a 和 b

max(max(a))

a.max() or np.nanmax(a)

的最大元素 a (对于MATLAB,ndims(a)<=2,如果存在NaN, nanmax 将忽略这些并返回最大值)

max(a)

a.max(0)

数组每列的最大元素 a

max(a,[],2)

a.max(1)

数组每行的最大元素数 a

max(a,b)

np.maximum(a, b)

比较 a 和 b 并返回每对的最大值

norm(v)

np.sqrt(v @ v) or np.linalg.norm(v)

向量的l2范数 v

a & b

logical_and(a,b)

逐元素和运算符(numpy ufunc) See note LOGICOPS

a | b

np.logical_or(a,b)

逐元素或运算符(numpy ufunc) See note LOGICOPS

bitand(a,b)

a & b

位与运算符(python-native和numpy-ufunc)

bitor(a,b)

a | b

按位或运算符(python-native和numpy-ufunc)

inv(a)

linalg.inv(a)

二维方阵的逆 a

pinv(a)

linalg.pinv(a)

二维阵列的伪逆 a

rank(a)

linalg.matrix_rank(a)

二维阵列的矩阵秩 a

a\b

linalg.solve(a, b) 如果 a 是正方形的; linalg.lstsq(a, b) 否则

对于x,a x=b的解

b/a

解决 a.T x.T = b.T 相反

x的解a=b,x的解

[U,S,V]=svd(a)

U, S, Vh = linalg.svd(a), V = Vh.T

奇异值分解 a

c=chol(a) where a==c'*c

c = linalg.cholesky(a) where a == c@c.T

二维阵列的Cholesky分解 (chol(a) 在MATLAB中,返回一个上三角二维数组,但是 cholesky 返回下三角(二维数组)

[V,D]=eig(a)

D,V = linalg.eig(a)

特征值 \lambda 和特征向量 \bar{{v}} 属于 a 在哪里 \lambda\bar{{v}}=\mathbf{{a}}\bar{{v}}

[V,D]=eig(a,b)

D,V = linalg.eig(a, b)

特征值 \lambda 和特征向量 \bar{{v}} 属于 a , b 在哪里? \lambda\mathbf{{b}}\bar{{v}}=\mathbf{{a}}\bar{{v}}

[V,D]=eigs(a,3)

D,V = eigs(a, k = 3)

找到 k=3 二维阵列的最大特征值和特征向量, a

[Q,R,P]=qr(a,0)

Q,R = linalg.qr(a)

QR分解

[L,U,P]=lu(a) where a==P'*L*U

P,L,U = linalg.lu(a) where a == P@L@U

LU分解(注:P(MATLAB)==转置(P(NumPy)))

conjgrad

cg

共轭梯度解算器

fft(a)

np.fft(a)

傅立叶变换 a

ifft(a)

np.ifft(a)

反傅立叶变换 a

sort(a)

np.sort(a) or a.sort(axis=0)

对二维数组的每一列进行排序, a

sort(a, 2)

np.sort(a, axis = 1) or a.sort(axis = 1)

对2D数组的每一行进行排序, a

[b,I]=sortrows(a,1)

I = np.argsort(a[:, 0]); b = a[I,:]

保存数组 a 作为数组 b 按第一列排序的行

x = Z\y

x = linalg.lstsq(Z, y)

对表格进行线性回归 \mathbf{{Zx}}=\mathbf{{y}}

decimate(x, q)

signal.resample(x, np.ceil(len(x)/q))

低通滤波下采样

unique(a)

np.unique(a)

数组中唯一值的向量 a

squeeze(a)

a.squeeze()

删除数组的单例维数 a . 请注意,MATLAB将始终返回2D或更高的数组,而NumPy将返回0D或更高的数组

笔记

子矩阵 :可以使用 ix_ 命令。E、 例如,对于二维阵列 a 人们可能会这样做: ind=[1, 3]; a[np.ix_(ind, ind)] += 100 .

HELP :没有直接等效的matlab which 命令,但是命令 help 和 numpy.source 通常会列出函数所在的文件名。python也有一个 inspect 模块(DO) import inspect )它提供了 getfile 这经常奏效。

INDEXING :MATLAB使用基于一的索引,因此序列的初始元素具有索引1。Python使用基于零的索引,因此序列的初始元素的索引为0。混乱和战争的产生是因为它们各有利弊。基于One的索引与人类常见的语言用法是一致的,即序列的“第一个”元素具有索引1。基于零的索引 simplifies indexing . 也见 a text by prof.dr. Edsger W. Dijkstra .

RANGES :在MATLAB中, 0:5 可以同时用作范围文本和“切片”索引(在括号内);但是,在Python中,构造如下 0:5 可以 only 用作切片索引(在方括号内)。所以有点古怪 r_ 对象的创建允许NumPy具有类似的简洁范围构造机制。请注意 r_ 不是像函数或构造函数那样调用,而是 索引的 使用方括号,这允许在参数中使用python的slice语法。

LOGICOPS : & or | in NumPy is bitwise AND/OR, while in MATLAB & and | are logical AND/OR. The two can appear to work the same, but there are important differences. If you would have used MATLAB's & or | operators, you should use the NumPy ufuncs logical_and/logical_or . MATLAB与NumPy的显著差异 & 和 | 操作员包括:

  • Non-logical {0,1} inputs: NumPy's output is the bitwise AND of the inputs. MATLAB treats any non-zero value as 1 and returns the logical AND. For example (3 & 4) in NumPy is 0, while in MATLAB both 3 and 4 are considered logical true and (3 & 4) returns 1.

  • 优先级:NumPy的&operator的优先级高于逻辑运算符,如 < 和 > MATLAB则相反。

如果您知道自己有布尔参数,可以不使用NumPy的位运算符,但要小心使用括号,如下所示: z = (x > 1) & (x < 2) . 无NumPy运算符的形式 logical_and 和 logical_or 是Python设计的不幸结果。

重塑和线性索引 :MATLAB始终允许使用标量或线性索引访问多维数组,NumPy则不允许。线性指标在MATLAB程序中很常见。 find() 在矩阵上返回它们,而NumPy的find的行为则不同。在转换MATLAB代码时,可能需要首先将矩阵重塑为线性序列,执行一些索引操作,然后再重塑回来。由于重塑(通常)会在同一个存储上生成视图,因此应该可以相当有效地执行此操作。注意,NumPy中reformate使用的扫描顺序默认为“C”顺序,而MATLAB使用Fortran顺序。如果你只是简单地转换成一个线性序列然后返回,这并不重要。但是,如果您要从依赖于扫描顺序的MATLAB代码转换重塑,则此MATLAB代码: z = reshape(x,3,4); 应该成为 z = x.reshape(3,4,order='F').copy() 在 NumPy 。

“array”还是“matrix”?我应该使用哪个?

过去,numpy提供了一种特殊的矩阵类型, np.matrix 它是ndarray的一个子类,它使二元运算成为线性代数运算。您可能会看到它在某些现有代码中使用,而不是 np.array . 那么,使用哪一个呢?

简短回答

使用数组 .

  • 它们支持MATLAB支持的多维数组代数

  • 它们是NumPy的标准向量/矩阵/张量类型。许多NumPy函数返回数组,而不是矩阵。

  • 元素运算和线性代数运算之间有着明显的区别。

  • 如果愿意,您可以使用标准向量或行/列向量。

在Python3.5之前,使用数组类型的唯一缺点是必须使用 dot 而不是 * 乘(减)两个张量(标量积、矩阵矢量乘等)。由于python 3.5,您可以使用矩阵乘法 @ 操作员。

鉴于上述情况,我们打算取消预测 matrix 最终。

长回答

numpy包含两个 array 类与A matrix 班级。这个 array 类是用于多种数值计算的通用N维数组,而 matrix 专门用于促进线性代数计算。实际上,两者之间只有少数几个关键区别。

  • 算子 * 和 @ 功能 dot() 和 multiply() :

    • 为了 array , ``*`` means element-wise multiplication ,同时 ``@`` means matrix multiplication ;它们具有相关功能 multiply() 和 dot() . (在Python 3.5之前, @ 不存在,必须使用 dot() 用于矩阵乘法)。

    • 为了 matrix , ``*`` means matrix multiplication 对于元素乘法,必须使用 multiply() 功能。

  • 向量处理(一维数组)

    • 为了 array , the 矢量形状1Xn、nx1和n都是不同的。 . 像这样的操作 A[:,1] 返回形状n的一维数组,而不是形状nx1的二维数组。一维转置 array 什么也不做。

    • 为了 matrix , one-dimensional arrays are always upconverted to 1xN or Nx1 matrices (行或列向量)。 A[:,1] 返回形状为nx1的二维矩阵。

  • 高维阵列的处理(ndim>2)

    • array 物体 can have number of dimensions > 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的第三方代码返回的类型。

    • :) 在家里处理任何尺寸的数据。

    • :) 如果你熟悉的话,在语义上更接近张量代数。

    • :) All operations (*, /, `` + - 等等)是元素方面的。

    • :( 稀疏矩阵来自 scipy.sparse 不要与数组进行很好的交互。

  • matrix

    • :\\ 行为更像MATLAB矩阵。

    • <:( 二维的最大值。保存所需的三维数据 array 或者是一个python列表 matrix .

    • <:( 二维的最小值。你不能有向量。它们必须转换为单列或单行矩阵。

    • <:( 自从 array 是numpy中的默认值,某些函数可能返回 array 即使你给他们一个 matrix 作为一个论点。这种情况不应该发生在numpy函数中(如果是bug),但是基于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