Numpy教程
Python中用于科学计算的核心库。numpy(Numerical Python)
提供了python对多维数组对象的支持:ndarray
,具有矢量运算能力,快速、节省空间。numpy支持高级大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
基础篇
NumPy的主要对象是同种元素的多维数组。这是一个所有的元素都是一种类型、通过一个正整数元组索引的元素表格(通常是元素是数字)。在NumPy中维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。
NumPy的数组类被称作 ndarray 。通常被称作数组。注意numpy.array和标准Python库类array.array并不相同,后者只处理一维数组和提供少量功能。更多重要ndarray对象属性有:
- ndarray.ndim
数组轴的个数,在python的世界中,轴的个数被称作秩 - ndarray.shape
数组的维度。这是一个指示数组在每个维度上大小的整数元组。例如一个n排m列的矩阵,它的shape属性将是(n,m),这个元组的长度显然是秩,即维度或者ndim属性 - ndarray.size
数组元素的总个数,等于shape属性中元组元素的乘积。 - ndarray.dtype
一个用来描述数组中元素类型的对象,可以通过创造或指定dtype使用标准Python类型。另外NumPy提供它自己的数据类型。 - ndarray.itemsize
数组中每个元素的字节大小。例如,一个元素类型为float64的数组itemsiz属性值为8(=64/8),又如,一个元素类型为complex32的数组item属性为4(=32/8). - ndarray.data
包含实际数组元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用数组中的元素。
一个例子:
1 | from numpy import * |
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
<class 'numpy.ndarray'>
a.ndim 2
a.shape (3, 5)
a.size 15
a.dtype int64
a.itemsize 8
a.data <memory at 0x7f1a641e17e0>
创建数组
使用 array 函数
使用 array 函数从常规的Python列表和元组创造数组。所创建的数组类型由原序列中的元素类型推导而来。
1 | #from numpy import * # 申明为*,不需要前缀 |
a [[ 1 2 3 4]
[ 5 6 7 8]
[10 2 3 4]]
b [ 1.2 3.5 5.1]
c: [[1 2 3 4]
[4 5 6 7]]
d [ 1.+0.j 2.+0.j 3.+0.j 4.+0.j]
使用占位符创建
- 通常,数组的元素开始都是未知的,但是它的大小已知。因此,NumPy提供了一些使用占位符创建数组的函数。这最小化了扩展数组的需要和高昂的运算代价。
- 函数zero创建一个全是0的数组,函数ones创建一个全1的数组,函数empty创建一个内容随机并且依赖与内存状态的数组。默认创建的数组类型(dtype)都是float64。
1 | print(np.zeros((3, 4))) |
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]
[[ 6.90466352e-310 6.90466352e-310]]
使用arange 函数
为了创建一个数列,NumPy提供一个类似arange的函数返回数组而不是列表:
1 | print(np.arange(10, 30, 5)) |
[10 15 20 25]
[ 0. 0.3 0.6 0.9 1.2 1.5 1.8 2.1 2.4 2.7]
使用 lineapce 函数
当arange
使用浮点数参数时,由于有限的浮点数精度,通常无法预测获得的元素个数。因此,最好使用函数linspace
去接收我们想要的元素个数来代替用range
来指定步长。
1 | from numpy import pi |
[ 0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. ]
[ 0.00000000e+00 6.42787610e-01 9.84807753e-01 8.66025404e-01
3.42020143e-01 -3.42020143e-01 -8.66025404e-01 -9.84807753e-01
-6.42787610e-01 -2.44929360e-16]
其它函数array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, rand, randn, fromfunction, fromfile, 赋值拷贝。
打印数组
当你打印一个数组,NumPy以类似嵌套列表的形式显示它,但是呈以下布局:
- 最后的轴从左到右打印
- 次后的轴从顶向下打印
- 剩下的轴从顶向下打印,每个切片通过一个空行与下一个隔开
一维数组被打印成行,二维数组成矩阵,三维数组成矩阵列表。
1 | a = np.arange(6)# 1d array |
[0 1 2 3 4 5]
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
[ 0 1 2 ..., 9997 9998 9999]
基本运算
数组的算术运算是按元素的。新的数组被创建并且被结果填充。NumPy中的乘法运算符 * 指示按元素计算,矩阵乘法可以使用 dot 函数或创建矩阵对象实现。
1 | a = np.array([1, 2, 3, 4]) |
b [0 1 2 3]
c [1 1 1 1]
b**2 [0 1 4 9]
10*np.sin(a) [ 8.41470985 9.09297427 1.41120008 -7.56802495]
a<35 [ True True True True]
1 | # NumPy中的乘法运算符*指示按元素计算,矩阵乘法可以使用dot函数或创建矩阵对象实现 |
[0 1 2 3 4 5]
A*B [[2 0]
[0 4]]
A.dot(B) [[5 4]
[3 4]]
np.dot(A, B) [[5 4]
[3 4]]
1 | # 有些操作符像+=和*=被用来更改已存在数组而不创建一个新的数组。 |
[[3 3 3]
[3 3 3]]
[[ 3.77601215 3.67874255 3.09996677]
[ 3.33283587 3.62279173 3.90198359]]
1 | # 当运算的是不同类型的数组时,结果数组靠近更普遍和精确的已知数组(这种行为叫做upcast)。 |
[1 1 1]
float64
c [ 1. 2.57079633 4.14159265]
c dtype name float64
[ 0.54030231+0.84147098j -0.84147098+0.54030231j -0.54030231-0.84147098j]
d dtype name complex128
e: [[ 0.48800489 0.55796234 0.16459517]
[ 0.40017365 0.41096132 0.01136693]]
e.sum:2.03306428928 e.max:0.557962337045 e.min:0.0113669291358
1 | # 这些运算默认应用到数组好像它就是一个数字组成的列表,无关数组的形状。然而,指定axis参数你可以吧运算应用到数组指定的轴上: |
b [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
b.sum(axis=0): [12 15 18 21]
b.sum(axis=1): [ 6 22 38]
b.min(axis=0): [0 1 2 3]
b.min(axis=1): [0 4 8]
b.max(axis=0): [ 8 9 10 11]
b.max(axis=1): [ 3 7 11]
b.cumsum(axis=0): [[ 0 1 2 3]
[ 4 6 8 10]
[12 15 18 21]]
b.cumsum(axis=1): [[ 0 1 3 6]
[ 4 9 15 22]
[ 8 17 27 38]]
通用函数(ufunc)
NumPy提供常见的数学函数如sin,cos和exp。在NumPy中,这些叫作“通用函数”(ufunc)。在NumPy里这些函数作用按数组的元素运算,产生一个数组作为输出。
1 | B = np.arange(3) |
[0 1 2]
[ 1. 2.71828183 7.3890561 ]
[ 0. 1. 1.41421356]
[ 2. 0. 6.]
更多函数all, alltrue, any, apply along axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, conjugate, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sometrue, sort, std, sum, trace, transpose, var, vdot, vectorize, where
索引,切片和迭代(Indexing, Slicing and Iterating)
一维 数组可以被索引、切片和迭代,就像 列表 和其它Python序列。
一维数组的索引:与Python的列表索引功能相似
1 | a = np.arange(10)**2 |
[ 0 1 4 9 16 25 36 49 64 81]
4
[ 4 9 16]
[-1000 1 -1000 9 -1000 25 36 49 64 81]
[ 81 64 49 36 25 -1000 9 -1000 1 -1000]
nan
1.0
nan
2.08008382305
nan
2.92401773821
3.30192724889
3.65930571002
4.0
4.32674871092
/opt/conda/lib/python3.6/site-packages/ipykernel_launcher.py:9: RuntimeWarning: invalid value encountered in power
if __name__ == '__main__':
多维 数组可以每个轴有一个索引。这些索引由一个逗号分割的元组给出。(二维数组: 纵轴,横轴)
多维数组的索引:1
2
3arr[r1:r2, c1:c2]
arr[1,1] 等价 arr[1][1]
[:] 代表某个维度的数据
1 | def f(x, y): |
[[ 0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]]
b[2,3]: 23
b[0:5, 1]: [ 1 11 21 31 41]
b[:, 1]: [ 1 11 21 31 41]
b[1:3, : ]: [[10 11 12 13]
[20 21 22 23]]
b[-1]: [40 41 42 43]
b[i]
中括号中的表达式被当作i和一系列:,来代表剩下的轴。NumPy也允许你使用“点”像b[i,...]
。- dot(…)代表许多产生一个完整的索引元组必要的分号。如果x是秩为5的数组(即它有5个轴),那么:
x[1,2,…]
等同于x[1,2,:,:,:]
,x[…,3]
等同于x[:,:,:,:,3]
x[4,…,5,:]
等同x[4,:,:,5,:]
.
1 | c = np.array([[[0, 1, 2], |
(2, 2, 3)
[[100 101 102]
[110 111 112]]
[[ 2 13]
[102 112]]
1 | # 迭代多维数组是就第一个轴而言的: |
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]
[[ 0 1 2]
[10 12 13]]
[[100 101 102]
[110 111 112]]
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43
0
1
2
10
12
13
100
101
102
110
111
112
更多操作 Indexing, Indexing (reference), newaxis, ndenumerate, indices
形状操作(shape manipulation)
改变数组的形状
一个数组的形状由它每个轴上的元素个数给出:
1 | a = np.floor(10*np.random.random((3,4))) |
[[ 2. 6. 1. 9.]
[ 3. 9. 1. 5.]
[ 2. 4. 0. 2.]]
(3, 4)
a.ravel(): [ 2. 6. 1. 9. 3. 9. 1. 5. 2. 4. 0. 2.]
orginal a: [[ 2. 6. 1. 9.]
[ 3. 9. 1. 5.]
[ 2. 4. 0. 2.]]
a.reshape(6, 2): [[ 2. 6.]
[ 1. 9.]
[ 3. 9.]
[ 1. 5.]
[ 2. 4.]
[ 0. 2.]]
orginal a: [[ 2. 6. 1. 9.]
[ 3. 9. 1. 5.]
[ 2. 4. 0. 2.]]
a.T: [[ 2. 3. 2.]
[ 6. 9. 4.]
[ 1. 1. 0.]
[ 9. 5. 2.]]
orginal a: [[ 2. 6. 1. 9.]
[ 3. 9. 1. 5.]
[ 2. 4. 0. 2.]]
a.T.shape: (4, 3)
a.shape: (3, 4)
a.transpose(): [[ 2. 3. 2.]
[ 6. 9. 4.]
[ 1. 1. 0.]
[ 9. 5. 2.]]
由ravel()
展平的数组元素的顺序通常是“C风格”
的,就是说,最右边的索引变化得最快,所以元素a[0,0]
之后是a[0,1]
。如果数组被改变形状(reshape)
成其它形状,数组仍然是“C风格”的。NumPy通常创建一个以这个顺序保存数据的数组,所以ravel()
将总是不需要复制它的参数。但是如果数组是通过切片其它数组或有不同寻常的选项时,它可能需要被复制。函数reshape()
和ravel()
还可以被同过一些可选参数构建成FORTRAN
风格的数组,即最左边的索引变化最快。
reshape
函数改变参数形状并返回它,而resize
函数改变数组自身,原本函数。
如果在改变形状操作中一个维度被给做-1,其维度将自动被计算
1 | print('original a', a) |
original a [[ 2. 6.]
[ 1. 9.]
[ 3. 9.]
[ 1. 5.]
[ 2. 4.]
[ 0. 2.]]
b: [[ 2. 6. 1. 9. 3. 9.]
[ 1. 5. 2. 4. 0. 2.]]
original a: [[ 2. 6.]
[ 1. 9.]
[ 3. 9.]
[ 1. 5.]
[ 2. 4.]
[ 0. 2.]]
[[ 2. 6.]
[ 1. 9.]
[ 3. 9.]
[ 1. 5.]
[ 2. 4.]
[ 0. 2.]]
[[ 2. 6. 1.]
[ 9. 3. 9.]
[ 1. 5. 2.]
[ 4. 0. 2.]]
See also
ndarray.shape, reshape, resize, ravel
组合(stack)不同的数组
几种方法可以沿不同轴将数组堆叠在一起
1 | a = np.floor(10*np.random.random((2, 2))) |
original a: [[ 4. 3.]
[ 4. 5.]]
original b: [[ 0. 0.]
[ 0. 0.]]
[[ 4. 3.]
[ 4. 5.]
[ 0. 0.]
[ 0. 0.]]
[[ 4. 3. 0. 0.]
[ 4. 5. 0. 0.]]
1 | # 函数column_stack以列将一维数组合成二维数组,它等同与vstack对一维数组。 |
np.column_stack((a, b)): [[ 2. 3.]
[ 4. 8.]]
np.hstack((a, b)): [ 2. 4. 3. 8.]
np.vstack((a, b)): [[ 2. 4.]
[ 3. 8.]]
a[:, newaxis]: [[ 2.]
[ 4.]]
np.column_stack((a[:,newaxis],b[:,newaxis])): [[ 2. 3.]
[ 4. 8.]]
[[ 2. 3.]
[ 4. 8.]]
1 | # Note |
[1 2 3 0 4]
将一个数组分割(split)成几个小数组
使用hsplit
你能将数组沿着它的水平轴分割,或者指定返回相同形状数组的个数,或者指定在哪些列后发生分割:
1 | a=np.floor(10*np.random.random((2, 12))) |
[[ 4. 9. 3. 1. 3. 6. 7. 6. 4. 3. 2. 8.]
[ 4. 0. 2. 1. 0. 1. 1. 7. 8. 1. 8. 4.]]
[array([[ 4., 9., 3., 1.],
[ 4., 0., 2., 1.]]), array([[ 3., 6., 7., 6.],
[ 0., 1., 1., 7.]]), array([[ 4., 3., 2., 8.],
[ 8., 1., 8., 4.]])]
[array([[ 4., 9., 3.],
[ 4., 0., 2.]]), array([[ 1.],
[ 1.]]), array([[ 3., 6., 7., 6., 4., 3., 2., 8.],
[ 0., 1., 1., 7., 8., 1., 8., 4.]])]
复制与视图(Copies and Views)
当运算和处理数组时,它们的数据有时被拷贝到新的数组有时不是。这通常是新手的困惑之源。这有三种情况:
完全不拷贝
简单的赋值不拷贝数组对象或它们的数据。
1 | a = np.arange(12) |
True
(3, 4)
139751323982384
139751323982384
None
视图(view)和浅复制
不同的数组对象分享同一个数据。视图方法view()
创造一个新的数组对象指向同一数据。
1 | print(a) |
[[ 0 1 2 3]
[1234 5 6 7]
[ 8 9 10 11]]
c: [[ 0 1 2 3]
[1234 5 6 7]
[ 8 9 10 11]]
c is a: False
c.base is a: True
c.flags.owndata: False
a.flags.owndata: False
(2, 6)
(3, 4)
c: [[ 0 1 2 3 1234 5]
[ 6 7 8 9 10 11]]
a: [[ 0 1 2 3]
[1234 5 6 7]
[ 8 9 10 11]]
1 | # 切片数组返回它的一个视图: |
[[10 10]
[10 10]
[10 10]]
[[10 10]
[10 10]
[10 10]]
[[10 10 10 3]
[10 10 10 7]
[10 10 10 11]]
深复制(deep copy)
这个复制方法完全复制数组和它的数据。
1 | print(a) |
[[10 10 10 3]
[10 10 10 7]
[10 10 10 11]]
[[10 10 10 3]
[10 10 10 7]
[10 10 10 11]]
False
False
[[999 10 10 3]
[ 10 10 10 7]
[ 10 10 10 11]]
[[10 10 10 3]
[10 10 10 7]
[10 10 10 11]]
函数和方法(method)总览
这是个NumPy函数和方法分类排列目录。这些名字链接到NumPy示例,你可以看到这些函数起作用
- 创建数组
arange, array, copy, empty, empty_like, eye, fromfile, fromfunction, identity, linspace, logspace, mgrid, ogrid, ones, ones_like, r, zeros, zeros_like
- 转化
ndarray.astype, atleast_1d, atleast_2d, atleast_3d, mat
- 操作
array_split, column_stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, ndarray.item, newaxis, ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack
- 询问
all, any, nonzero, where
- 排序
argmax, argmin, argsort, max, min, ptp, searchsorted, sort
- 运算
choose, compress, cumprod, cumsum, inner, fill, imag, prod, put, putmask, real, sum
- 基本统计
cov, mean, std, var
- 基本线性代数
cross, dot, outer, svd, vdot
进阶
广播法则(rule)
- 广播法则能使通用函数有意义地处理不具有相同形状的输入。
- 广播第一法则是,如果所有的输入数组维度不都相同,一个“1”将被重复地添加在维度较小的数组上直至所有的数组拥有一样的维度。
- 广播第二法则确定长度为1的数组沿着特殊的方向表现地好像它有沿着那个方向最大形状的大小。对数组来说,沿着那个维度的数组元素的值理应相同。
- 应用广播法则之后,所有数组的大小必须匹配。更多网址
We will add the vector v to each row of the matrix x,
storing the result in the matrix y
对两个数组使用广播机制要遵守下列规则:
- 如果数组的秩不同,使用1来将秩较小的数组进行扩展,直到两个数组的尺寸的长度都一样。
- 如果两个数组在某个维度上的长度是一样的,或者其中一个数组在该维度上长度为1,那么我们就说这两个数组在该维度上是相容的。
- 如果两个数组在所有维度上都是相容的,他们就能使用广播。
- 如果两个输入数组的尺寸不同,那么注意其中较大的那个尺寸。因为广播之后,两个数组的尺寸将和那个较大的尺寸一样。
- 在任何一个维度上,如果一个数组的长度为1,另一个数组长度大于1,那么在该维度上,就好像是对第一个数组进行了复制
花哨的索引和索引技巧
NumPy比普通Python序列提供更多的索引功能。除了索引整数和切片,正如我们之前看到的,数组可以被整数数组和布尔数组索引。
通过数组索引
1 | a = np.arange(12)**2 |
a: [ 0 1 4 9 16 25 36 49 64 81 100 121]
[ 1 1 9 49 64]
[[ 9 25]
[49 81]]
1 | # 当被索引数组a是多维的时,每一个唯一的索引数列指向a的第一维。以下示例通过将图片标签用调色版转换成色彩图像展示了这种行为。 |
array([[[ 0, 0, 0],
[ 255, 0, 0],
[ 0, 255, 0],
[ 0, 0, 0]],
[[ 0, 0, 0],
[ 0, 0, 255],
[ 255, 255, 2555],
[ 0, 0, 0]]])
1 | # 我们也可以给出不不止一维的索引,每一维的索引数组必须有相同的形状。 |
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
a[i,j]: [[ 2 5]
[ 7 11]]
a[i,2]: [[ 2 6]
[ 6 10]]
a[:,j]: [[[ 2 1]
[ 3 3]]
[[ 6 5]
[ 7 7]]
[[10 9]
[11 11]]]
1 | # 自然,我们可以把i和j放到序列中(比如说列表)然后通过list索引。 |
[array([[0, 1],
[1, 2]]), array([[2, 1],
[3, 3]])]
1 | # 另一个常用的数组索引用法是搜索时间序列最大值 |
[ 20. 51.25 82.5 113.75 145. ]
[[ 0. 0.84147098 0.90929743 0.14112001]
[-0.7568025 -0.95892427 -0.2794155 0.6569866 ]
[ 0.98935825 0.41211849 -0.54402111 -0.99999021]
[-0.53657292 0.42016704 0.99060736 0.65028784]
[-0.28790332 -0.96139749 -0.75098725 0.14987721]]
[2 0 3 1]
[ 82.5 20. 113.75 51.25]
[ 0.98935825 0.84147098 0.99060736 0.6569866 ]
True
1 | # 你也可以使用数组索引作为目标来赋值: |
[0 1 2 3 4]
[0 0 2 0 0]
[2 1 3 3 4]
[1 1 3 3 4]
通过布尔数组索引
当我们使用整数数组索引数组时,我们提供一个索引列表去选择。通过布尔数组索引的方法是不同的我们显式地选择数组中我们想要和不想要的元素。
我们能想到的使用布尔数组的索引最自然方式就是使用和原数组一样形状的布尔数组。
1 | a = np.arange(12).reshape(3, 4) |
[[False False False False]
[False True True True]
[ True True True True]]
[ 5 6 7 8 9 10 11]
[[0 1 2 3]
[4 0 0 0]
[0 0 0 0]]
1 | # 例子 |
第二种通过布尔来索引的方法更近似于整数索引;对数组的每个维度我们给一个一维布尔数组来选择我们想要的切片。
1 | a = np.arange(12).reshape(3, 4) |
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
a[b1,:]: [[ 4 5 6 7]
[ 8 9 10 11]]
a[b1]: [[ 4 5 6 7]
[ 8 9 10 11]]
a[:,b2]: [[ 0 2]
[ 4 6]
[ 8 10]]
a[b1,b2]: [ 4 10]
1 | import numpy as np |
[[ 2 2 4]
[ 5 5 7]
[ 8 8 10]
[11 11 13]]
ix_()
函数
ix_
函数可以为了获得多元组的结果而用来结合不同向量。例如,如果你想要用所有向量a、b和c元素组成的三元组来计算a+b*c
:
1 | a = np.array([2,3,4,5]) |
ax: [[[2]]
[[3]]
[[4]]
[[5]]]
bx: [[[8]
[5]
[4]]]
cx: [[[5 4 6 8 3]]]
(4, 1, 1) (1, 3, 1) (1, 1, 5)
result: [[[42 34 50 66 26]
[27 22 32 42 17]
[22 18 26 34 14]]
[[43 35 51 67 27]
[28 23 33 43 18]
[23 19 27 35 15]]
[[44 36 52 68 28]
[29 24 34 44 19]
[24 20 28 36 16]]
[[45 37 53 69 29]
[30 25 35 45 20]
[25 21 29 37 17]]]
17
17
1 | # 你也可以实行如下简化: |
array([[[15, 14, 16, 18, 13],
[12, 11, 13, 15, 10],
[11, 10, 12, 14, 9]],
[[16, 15, 17, 19, 14],
[13, 12, 14, 16, 11],
[12, 11, 13, 15, 10]],
[[17, 16, 18, 20, 15],
[14, 13, 15, 17, 12],
[13, 12, 14, 16, 11]],
[[18, 17, 19, 21, 16],
[15, 14, 16, 18, 13],
[14, 13, 15, 17, 12]]])
用字符串索引
See Structured arrays.
线性代数
简单数组运算
参考numpy文件夹中的linalg.py获得更多信息
1 | import numpy as np |
[[ 1. 2.]
[ 3. 4.]]
[[ 1. 3.]
[ 2. 4.]]
[[-2. 1. ]
[ 1.5 -0.5]]
[[ 1. 0.]
[ 0. 1.]]
[[-1. 0.]
[ 0. -1.]]
2.0
矩阵类
这是一个关于矩阵类的简短介绍。
1 | A = np.matrix('1.0 2.0;3.0 4.0') |
[[ 1. 2.]
[ 3. 4.]]
<class 'numpy.matrixlib.defmatrix.matrix'>
[[ 1. 3.]
[ 2. 4.]]
[[ 5.]
[ 7.]]
[[ 19.]
[ 43.]]
[[-2. 1. ]
[ 1.5 -0.5]]
索引:比较矩阵和二维数组
注意NumPy中数组和矩阵有些重要的区别。NumPy提供了两个基本的对象:一个N维数组对象和一个通用函数对象。其它对象都是建构在它们之上的。特别的,矩阵是继承自NumPy数组对象的二维数组对象。对数组和矩阵,索引都必须包含合适的一个或多个这些组合:整数标量、省略号(ellipses)、整数列表;布尔值,整数或布尔值构成的元组,和一个一维整数或布尔值数组。矩阵可以被用作矩阵的索引,但是通常需要数组、列表或者其它形式来完成这个任务。
像平常在Python中一样,索引是从0开始的。传统上我们用矩形的行和列表示一个二维数组或矩阵,其中沿着0轴的方向被穿过的称作行,沿着1轴的方向被穿过的是列。
让我们创建数组和矩阵用来切片:
1 | A=np.arange(12) |
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
<class 'numpy.ndarray'> <class 'numpy.matrixlib.defmatrix.matrix'>
现在,让我们简单的切几片。基本的切片使用切片对象或整数。例如,A[:]
和M[:]
的求值将表现得和Python索引很相似。然而要注意很重要的一点就是NumPy切片数组不创建数据的副本;切片提供统一数据的视图。
1 | print(A[:],A[:].shape) |
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]] (3, 4)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]] (3, 4)
[1 5 9]
(3,)
[[1]
[5]
[9]]
(3, 1)
注意最后两个结果的不同。对二维数组使用一个冒号产生一个一维数组,然而矩阵产生了一个二维矩阵。例如,一个M[2,:]
切片产生了一个形状为(1,4)的矩阵,相比之下,一个数组的切片总是产生一个最低可能维度11的数组。例如,如果C是一个三维数组,C[...,1]
产生一个二维的数组而C[1,:,1]
产生一个一维数组。从这时开始,如果相应的矩阵切片结果是相同的话,我们将只展示数组切片的结果。
假如我们想要一个数组的第一列和第三列,一种方法是使用列表切片:
1 | print(A[:,[1,3]]) |
[[ 1 3]
[ 5 7]
[ 9 11]]
[[ 1 3]
[ 5 7]
[ 9 11]]
[[ 5 7]
[ 9 11]]
[[ 5 7]
[ 9 11]]
[False False True True]
[[ 2 3]
[ 6 7]
[10 11]]
1 | # 就是我们想要的!但是索引矩阵没这么方便。 |
[[False False True True]]
[]
[[ 2 3]
[ 6 7]
[10 11]]
[ 6 11]
[[ 6 11]]
[[ 6 7]
[10 11]]
[[ 6 7]
[10 11]]
技巧和提示
“自动”改变形状
更改数组的维度,你可以省略一个尺寸,它将被自动推导出来。
1 | a = np.arange(30) |
(2, 5, 3)
[[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]
[12 13 14]]
[[15 16 17]
[18 19 20]
[21 22 23]
[24 25 26]
[27 28 29]]]
向量组合(stacking)
我们如何用两个相同尺寸的行向量列表构建一个二维数组?在MATLAB中这非常简单:如果x和y是两个相同长度的向量,你仅仅需要做m=[x;y]
。在NumPy中这个过程通过函数column_stack、dstack、hstack和vstack来
完成,取决于你想要在那个维度上组合。例如:
1 | x=np.arange(0, 10, 2) |
[[0 2 4 6 8]
[0 1 2 3 4]]
[0 2 4 6 8 0 1 2 3 4]
直方图(histogram)
NumPy中histogram函数应用到一个数组返回一对变量:直方图数组和箱式向量。注意:matplotlib
也有一个用来建立直方图的函数(叫作hist,正如matlab中一样)与NumPy中的不同。主要的差别是pylab.hist自动绘制直方图,而numpy.histogram
仅仅产生数据。
1 | import numpy |