前言
在有关数据处理中经常会使用到numpy来进行对应矩阵的计算,而numpy的维度,广播机制还有axis等一直懵懵懂懂,所以就在此做一个小整理,搞清楚这个问题,并方便后续查阅

1、numpy中维度的表示

1)一维

1
2
3
4
>>> import numpy as np
>>> a=np.array([1,2,3])
>>> a.shape
(3,)

2)二维

1
2
3
4
5
>>> import numpy as np
>>> b=np.array([[1,2,3],
... [3,4,5]])
>>> b.shape
(2, 3)

3)三维

1
2
3
4
5
6
7
8
9
>>> import numpy as np
>>> c=np.array([[[5,8,0,1],
... [3,5,5,3],
... [2,3,4,0]],
... [[1,2,3,2],
... [3,4,5,5],
... [1,1,8,3]]])
>>> c.shape
(2, 3, 4)

array.shape属性表示一个array对象(我们通常称为矩阵,下称矩阵)从高到低各个维度对应的值

2、axis的用法

我们已经通过shape获得一个矩阵的各个维度的值,因此可以通过下标方式对矩阵的特定元素进行索引,还可以使用axis对各个维度上进行索引。
例如(2,3,4),axis=0,1,2各自对应该tuple上的元素,沿着axis对应的维度的方向遍历矩阵并完成指定的操作。

1
2
3
4
>>> c.max(axis=0)
array([[5, 8, 3, 2],
[3, 5, 5, 5],
[2, 3, 8, 3]])

我们来理解一下,首先c.max.shape=(3,4),对原来的c沿着axis=0做了一个切片,所以最高维度根据max操作被分解,此时该矩阵降维成二维,每一个元素对应原始原始矩阵在axis=0方向上对应元素中最大值,举几个例子:
c.max[0,0]=5=max(c[0,0,0]=5,c[1,0,0]=1)
c.max[1,0]=3=max(c[0,1,0]=3,c[1,1,0]=3)
c.max[2,2]=8=max(c[0,2,2]=4,c[1,2,2]=8)
既然如此,我想看到这里我们应该能知道axis=1的结果应该是什么了

1
2
3
>>> c.max(axis=1)
array([[5,8,5,3],
[3,4,8,5]])

c.max.shape=(2, 4),举个例子来看其中一个值是如何计算出来的:
c.max[1,3]=8=max(c[1,0,3]=3,c[1,1,3]=5,c[1,2,3]=8)

可以试着自己写写c.max(axis=2)的结果

1
2
3
>>> c.max(axis=2)
array([[8,5,4],
[3,5,8]])

相信看到这里应该已经能够明白axis的定义了,也就是将原始的矩阵根据axis指定的维度进行切片,被指定的维度坍缩,矩阵降维,根据指定维度索引进行相关的操作。

  • 如果我们想要矩阵每一行行内进行操作得到某个结果,那么应该让axis=shape中最末元素的索引(python支持负数切片机制)

3、广播机制

首先在数学上的矩阵运算需要满足矩阵维度严格相等,但是numpy中这一定义被放宽,只要两个矩阵满足如下定义都可以进行相关运算
对于矩阵a和b,将二者的shape靠右对齐,对于对应的维度,如果二者值相等或者其中一个的值为1,则二者在该维度上是兼容的,对于不存在的维度,则默认是兼容的。

接着numpy会对子维度的矩阵进行扩维,也就是直接复制元素使得参与运算的二者维度一致,从而可以进行相关的运算。

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
>>> a+b
array([[2, 4, 6],
[4, 6, 8]])
>>> d=np.array([[1,4,5],
... [2,3,3],
... [2,4,7]])
>>> d.shape
(3, 3)
# b和d是无法直接进行运算的,可以采用如下方式
>>> e=np.expand_dims(b,axis=1)
>>> e
array([[[1, 2, 3]],

[[3, 4, 5]]])
>>> e.shape
(2, 1, 3)
>>> d+e
array([[[ 2, 6, 8],
[ 3, 5, 6],
[ 3, 6, 10]],

[[ 4, 8, 10],
[ 5, 7, 8],
[ 5, 8, 12]]])
>>> (d+e).shape
(2, 3, 3)