# 从 Matlab 到 Numpy ## Numpy 和 Matlab 比较 **`Numpy`** 和 **`Matlab`** 有很多相似的地方,但 **`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, Nx1`,`A[:,1]` 返回的是二维 `Nx1` 矩阵 * 高维数组 * `array`:支持大于2的维度 * `matrix`:维度只能为2 * 属性 * `array`:`.T` 表示转置 * `matrix`:`.H` 表示复共轭转置,`.I` 表示逆,`.A` 表示转化为 `array` 类型 * 构造函数 * `array`:`array` 函数接受一个(嵌套)序列作为参数——`array([[1,2,3],[4,5,6]])` * `matrix`:`matrix` 函数额外支持字符串参数——`matrix("[1 2 3; 4 5 6]")` 其优缺点各自如下: * **`array`** * `[GOOD]` 一维数组既可以看成列向量,也可以看成行向量。`v` 在 `dot(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]: ```py import numpy import numpy.matlib ``` In [2]: ```py a = numpy.ones(7) print a.shape print type(a) ``` ```py (7L,) ``` In [3]: ```py a = numpy.matlib.ones(7) print a.shape print type(a) ``` ```py (1L, 7L) ``` `mat` 函数将一个数组转化为矩阵: In [4]: ```py a = numpy.array([1,2,3]) b = numpy.mat(a) print type(b) ``` ```py ``` 有些函数被放到子模块中了,例如调用 `rand()` 函数需要使用 `numpy.random.rand()` (或者从 `matlib` 模块中生成矩阵): In [5]: ```py a = numpy.random.rand(10) print a ``` ```py [ 0.66007267 0.34794294 0.5040946 0.65044648 0.74763248 0.42486999 0.90922612 0.69071747 0.33541076 0.08570178] ``` ## 等效操作 假定我们已经这样导入了 `Numpy`: In [6]: ```py from numpy import * import scipy.linalg ``` 以下 `linalg` 表示的是 `numpy.linalg`,与 `scipy.linalg` 不同。 注意:**`MATLAB`** 与 **`Numpy`** 下标之间有这样几处不同: * `1-base` vs `0-base` * `()` vs `[]` * `MATLAB`:`beg(:step):end`,包含结束值 `end` * `Numpy`:`beg: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 n` 个 `a` | | `[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](http://wiki.scipy.org/NumPy_for_Matlab_Users#whichNotes)