从 Matlab 到 Numpy

Numpy 和 Matlab 比较

NumpyMatlab 有很多相似的地方,但 Numpy 并非 Matlab 的克隆,它们之间存在很多差异,例如:

MATLAB® Numpy
基本类型为双精度浮点数组,以二维矩阵为主 基本类型为 ndarray,有特殊的 matrix
1-based 索引 0-based 索引
脚本主要用于线性代数计算 可以使用其他的 Python 特性
采用值传递的方式进行计算
切片返回复制
采用引用传递的方式进行计算
切片返回引用
文件名必须和函数名相同 函数可以在任何地方任何文件中定义
收费 免费
2D,3D图像支持 依赖第三方库如 matplotlib
完全的编译环境 依赖于 Python 提供的编译环境

array 还是 matrix?

Numpy 中不仅提供了 array 这个基本类型,还提供了支持矩阵操作的类 matrix,但是一般推荐使用 array

  • 很多 numpy 函数返回的是 array,不是 matrix
  • array 中,逐元素操作和矩阵操作有着明显的不同
  • 向量可以不被视为矩阵

具体说来:

  • *, dot(), multiply()
    • array* -逐元素乘法,dot() -矩阵乘法
    • matrix* -矩阵乘法,multiply() -逐元素乘法
  • 处理向量
    • array:形状为 1xN, Nx1, N 的向量的意义是不同的,类似于 A[:,1] 的操作返回的是一维数组,形状为 N,一维数组的转置仍是自己本身
    • matrix:形状为 1xN, Nx1A[:,1] 返回的是二维 Nx1 矩阵
  • 高维数组
    • array:支持大于2的维度
    • matrix:维度只能为2
  • 属性
    • array.T 表示转置
    • matrix.H 表示复共轭转置,.I 表示逆,.A 表示转化为 array 类型
  • 构造函数
    • arrayarray 函数接受一个(嵌套)序列作为参数——array([[1,2,3],[4,5,6]])
    • matrixmatrix 函数额外支持字符串参数——matrix("[1 2 3; 4 5 6]")

其优缺点各自如下:

  • array

    • [GOOD] 一维数组既可以看成列向量,也可以看成行向量。vdot(A,v) 被看成列向量,在 dot(v,A) 中被看成行向量,这样省去了转置的麻烦
    • [BAD!] 矩阵乘法需要使用 dot() 函数,如: dot(dot(A,B),C) vs A*B*C
    • [GOOD] 逐元素乘法很简单: A*B
    • [GOOD] 作为基本类型,是很多基于 numpy 的第三方库函数的返回类型
    • [GOOD] 所有的操作 *,/,+,**,... 都是逐元素的
    • [GOOD] 可以处理任意维度的数据
    • [GOOD] 张量运算
  • matrix

    • [GOOD] 类似与 MATLAB 的操作
    • [BAD!] 最高维度为2
    • [BAD!] 最低维度也为2
    • [BAD!] 很多函数返回的是 array,即使传入的参数是 matrix
    • [GOOD] A*B 是矩阵乘法
    • [BAD!] 逐元素乘法需要调用 multiply 函数
    • [BAD!] / 是逐元素操作

当然在实际使用中,二者的使用取决于具体情况。

二者可以互相转化:

  • asarray :返回数组
  • asmatrix(或者mat) :返回矩阵
  • asanyarray :返回数组或者数组的子类,注意到矩阵是数组的一个子类,所以输入是矩阵的时候返回的也是矩阵

类 Matlab 函数

有很多类似的函数:

  • ones, zeros, empty, eye, rand, repmat

通常这些函数的返回值是 array,不过 numpy 提供了一个 matlib 的子模块,子模块中的这些函数返回值为 matrix

In [1]:
import numpy
import numpy.matlib
In [2]:
a = numpy.ones(7)

print a.shape
print type(a)
(7L,)
<type 'numpy.ndarray'>
In [3]:
a = numpy.matlib.ones(7)

print a.shape
print type(a)
(1L, 7L)
<class 'numpy.matrixlib.defmatrix.matrix'>

mat 函数将一个数组转化为矩阵:

In [4]:
a = numpy.array([1,2,3])

b = numpy.mat(a)

print type(b)
<class 'numpy.matrixlib.defmatrix.matrix'>

有些函数被放到子模块中了,例如调用 rand() 函数需要使用 numpy.random.rand() (或者从 matlib 模块中生成矩阵):

In [5]:
a = numpy.random.rand(10)
print a
[ 0.66007267  0.34794294  0.5040946   0.65044648  0.74763248  0.42486999
  0.90922612  0.69071747  0.33541076  0.08570178]

等效操作

假定我们已经这样导入了 Numpy

In [6]:
from numpy import *
import scipy.linalg

以下 linalg 表示的是 numpy.linalg,与 scipy.linalg 不同。

注意:MATLABNumpy 下标之间有这样几处不同:

  • 1-base vs 0-base
  • () vs []
  • MATLABbeg(:step):end,包含结束值 end
  • Numpybeg:end(:step),不包含结束值 end
MATLAB Numpy 注释
help func info(func)help(func)func?(IPython) 查看函数帮助
which func 查看函数在什么地方定义
type func source(func)func??(IPython) 查看函数源代码
a && b a and b 逻辑 AND
1*i, 1*j, 1i, 1j 1j 复数
eps spacing(1) 1 与最近浮点数的距离
ndims(a) ndim(a), a.ndim a 的维数
numel(a) size(a), a.size a 的元素个数
size(a) shape(a), a.shape a 的形状
size(a,n) a.shape[n-1] 第 n 维的大小
a(2,5) a[1,4] 第 2 行第 5 列元素
a(2,:) a[1], a[1,:] 第 2 行
a(1:5,:) a[0:5] 第 1 至 5 行
a(end-4:end,:) a[-5:] 后 5 行
a(1:3,5:9) a[0:3][:,4:9] 特定行列(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,:] 特定行列(3,5,...,21 行)
a(1:2:end,:) a[ ::2,:] 奇数行
a([1:end 1],:) a[r_[:len(a),0]] 将第一行添加到末尾
a.' a.T 转置
a ./ b a/b 逐元素除法
(a>0.5) (a>0.5) 各个元素是否大于 0.5
find(a>0.5) nonzero(a>0.5) 大于 0.5 的位置
a(a<0.5)=0 a[a<0.5]=0 小于 0.5 的设为 0
a(:) = 3 a[:] = 3 所有元素设为 3
y=x y=x.copy() 将 y 设为 x
y=x(2,:) y=x[1,:].copy() 注意值传递和引用传递的区别
y=x(:) y=x.flatten(1) 将矩阵变为一个向量,这里 1 表示沿着列进行转化
max(max(a)) a.max() 最大值
max(a) a.max(0) 每一列的最大值
max(a,[],2) a.max(1) 每一行的最大值
max(a,b) maximum(a,b) 逐元素比较,取较大的值
a & b logical_and(a, b) 逻辑 AND
bitand(a, b) a & b 逐比特 AND
inv(a) linalg.inv(a) a 的逆
pinv(a) linalg.inv(a) 伪逆
rank(a) linalg.matrix_rank(a)
a\b linalg.solve(a,b)(如果a是方阵),linalg.lstsq(a,b) a x = b
b/a 求解 a.T x.T = b.T x a = b
[U,S,V]=svd(a) U, S, Vh = linalg.svd(a), V = Vh.T 奇异值分解
chol(a) linalg.cholesky(a).T Cholesky 分解
[V,D]=eig(a) D,V = linalg.eig(a) 特征值分解
[V,D]=eig(a,b) V,D = scipy.linalg.eig(a,b)
[V,D]=eigs(a,k) 前 k 大特征值对应的特征向量
`` ``
`` ``
`` ``
`` ``
MATLAB numpy.array numpy.matrix 注释
[1,2,3;4,5,6] array([[1.,2.,3.],[4.,5.,6.]]) mat([[1.,2.,3.],[4.,5.,6.]]), mat('1,2,3;4,5,6') 2x3 矩阵
[a b;c d] vstack([hstack([a,b]), hsatck([c,d])]]) bmat('a b;c d') 分块矩阵构造
a(end) a[-1] a[:,-1][0,0] 最后一个元素
a' a.conj().T a.H 复共轭转置
a * b dot(a,b) a * b 矩阵乘法
a .* b a * b multiply(a,b) 逐元素乘法
a.^3 a**3 power(a,3) 逐元素立方
a(:,find(v>0.5)) a[:,nonzero(v>0.5)[0]] a[:,nonzero(v.A>0.5)[0]] 找出行向量 v>0.5 对应的 a 中的列
a(:,find(v>0.5)) a[:,v.T>0.5] a[:,v.T>0.5)] 找出列向量 v>0.5 对应的 a 中的列
a .* (a>0.5) a * (a>0.5) mat(a.A * (a>0.5).A) 将所有小于 0.5 的元素设为 0
1:10 arange(1.,11.), r_[1.:11.], r_[1:10:10j] mat(arange(1.,11.)), r_[1.:11., 'r'] 这里 1. 是为了将其转化为浮点数组
0:9 arange(10.), r_[:10.], r_[:9:10j] mat(arange(10.)), r_[:10., 'r']
[1:10]' arange(1.,11.)[:,newaxis] r_[1.:11.,'c'] 列向量
zeros, ones, eye, diag, linspace zeros, ones, eye, diag, linspace mat(...)
rand(3,4) random.rand(3,4) mat(...) 0~1 随机数
[x,y]=meshgrid(0:8,0:5) mgrid[0:9., 0:6.], meshgrid(r_[0:9.],r_[0:6.]) mat(...) 网格
ogrid[0:9.,0:6.], ix_(r_[0:9.],r_[0:6.]) mat() 建议在 Numpy 中使用
[x,y]=meshgrid([1,2,4],[2,4,5]) meshgrid([1,2,4],[2,4,5]) mat(...)
ix_([1,2,4],[2,4,5]) mat(...)
repmat(a, m, n) tile(a, (m,n)) mat(...) 产生 m x na
[a b] c_[a,b] concatenate((a,b),1) 列对齐连接
[a; b] r_[a,b] concatenate((a,b)) 行对齐连接
norm(v) sqrt(dot(v,v)), linalg.norm(v) sqrt(dot(v.A,v.A)), linalg.norm(v)
[Q,R,P]=qr(a,0) Q,R = scipy.linalg.qr(a) mat(...) QR 分解
[L,U,P]=lu(a) L,U = Sci.linalg.lu(a) mat(...) LU 分解
fft(a) fft(a) mat(...) FFT
ifft(a) ifft(a) mat(...) IFFT
sort(a) sort(a),a.sort mat(...) 排序

参考:http://wiki.scipy.org/NumPy_for_Matlab_Users#whichNotes