Files
ailearning/docs/da/051.md
2020-10-19 21:08:55 +08:00

260 lines
9.8 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 从 Matlab 到 Numpy
## Numpy 和 Matlab 比较
**`Numpy`** 和 **`Matlab`** 有很多相似的地方,但 **`Numpy`** 并非 **`Matlab`** 的克隆,它们之间存在很多差异,例如:
| `MATLAB®` | `Numpy` |
| --- | --- |
| 基本类型为双精度浮点数组,以二维矩阵为主 | 基本类型为 `ndarray`,有特殊的 `matrix` 类 |
| 1-based 索引 | 0-based 索引 |
| 脚本主要用于线性代数计算 | 可以使用其他的 **Python** 特性 |
| 采用值传递的方式进行计算
切片返回复制 | 采用引用传递的方式进行计算
切片返回引用 |
| 文件名必须和函数名相同 | 函数可以在任何地方任何文件中定义 |
| 收费 | 免费 |
| 2D3D图像支持 | 依赖第三方库如 `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,)
<type 'numpy.ndarray'>
```
In [3]:
```py
a = numpy.matlib.ones(7)
print a.shape
print type(a)
```
```py
(1L, 7L)
<class 'numpy.matrixlib.defmatrix.matrix'>
```
`mat` 函数将一个数组转化为矩阵:
In [4]:
```py
a = numpy.array([1,2,3])
b = numpy.mat(a)
print type(b)
```
```py
<class 'numpy.matrixlib.defmatrix.matrix'>
```
有些函数被放到子模块中了,例如调用 `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)