面向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库,包括: SciPyMatplotlibPandasOpenCV ,等等。此外,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中 TrueFalse ,而不是MATLAB的逻辑类型 10 .

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

从块构造矩阵 abcd

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结果是一个布尔值数组 FalseTrue .

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]

连接的列 ab

[a; b]

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

连接的行 ab

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)

比较 ab 并返回每对的最大值

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}} 属于 ab 在哪里? \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 命令,但是命令 helpnumpy.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_andlogical_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 什么也不做。

    • 为了 matrixone-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

使用不推荐的 matrixmatlib 功能:

# 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