• Axis 就是数组层级
  • 设 axis=i,则 Numpy 沿着第 i 个下标变化的方向进行操作
  • Axis 的应用

Axis 就是数组层级

要想理解 axis,首先我们先要弄清楚 “Numpy 中数组的维数” 和 “线性代数中矩阵的维数” 这两个概念以及它们之间的关系。在数学或者物理的概念中,dimensions 被认为是在空间中表示一个点所需要的最少坐标个数,但是在 Numpy 中,dimensions 指代的是数组的维数。比如下面这个例子:

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

这个 array 的维数只有 2,即 axis 轴有两个,分别是 axis=0 和 axis=1。如下图所示,该二维数组的第 0 维 (axis=0) 有三个元素 (左图),即 axis=0 轴的长度 length 为 3;第 1 维(axis=1) 也有三个元素(右图),即 axis=1 轴的长度 length 为 3。正是因为 axis=0、axis=1 的长度都为 3,矩阵横着竖着都有 3 个数,所以该矩阵在线性代数是 3 维的(rank 秩为 3)。

因此,axis 就是数组层级。

当 axis=0,该轴上的元素有 3 个 (数组的 size 为 3)

a[0]a[1]a[2]

当 axis=1,该轴上的元素有 3 个 (数组的 size 为 3)

a[0][0]a[0][1]a[0][2]

(或者a[1][0]a[1][1]a[1][2]

(或者a[2][0]a[2][1]a[2][2]

再比如下面 shape 为 (3,2,4) 的 array:

1
2
3
4
5
6
7
8
9
10
11
12
>>> b = np.array([[[1,2,3,4],[1,3,4,5]],[[2,4,7,5],[8,4,3,5]],[[2,5,7,3],[1,5,3,7]]])
>>> b
array([[[1, 2, 3, 4],
[1, 3, 4, 5]],

[[2, 4, 7, 5],
[8, 4, 3, 5]],

[[2, 5, 7, 3],
[1, 5, 3, 7]]])
>>> b.shape
(3, 2, 4)

这个 shape(用 tuple 表示)可以理解为在每个轴(axis)上的 size,也即占有的长度(length)。为了更进一步理解,我们可以暂时把多个 axes 想象成多层 layers。axis=0 表示第一层 (下图黑色框框),该层数组的 size 为 3,对应轴上的元素 length = 3;axis=1 表示第二层 (下图红色框框),该层数组的 size 为 2,对应轴上的元素 length = 2;axis=2 表示第三层 (下图蓝色框框),对应轴上的元素 length = 4。

设 axis=i,则 Numpy 沿着第 i 个下标变化的方向进行操作

  1. 二维数组示例:

比如np.sum(a, axis=1),结合下面的数组, a[0][0]=1、a[0][1]=2、a[0][2]=3 ,下标会发生变化的方向是数组的第一维。

我们往下标会变化的方向,把元素相加后即可得到最终结果:

1
2
3
4
5
[
[6],
[9],
[16]
]
  1. 三维数组示例:

再举个例子,比如下边这个np.shape(a)=(3,2,4)的 3 维数组,该数组第 0 维的长度为 3(黑色框框),再深入一层,第 1 维的长度为 2(红色框框),再深入一层,第 2 维的长度为 4(蓝色框框)。

如果我们要计算np.sum(a, axis=1),在第一个黑色框框中,

下标的变化方向如下所示:

所以,我们要把上下两个红色框框相加起来

按照同样的逻辑处理第二个和第三个黑色的框框,可以得出最终结果:

所以,依然是我们前边总结的那一句话,设 axis=i,则 Numpy 沿着第 i 个下标变化的方向进行操作。

  1. 四维数组示例:

比如下面这个巨复杂的 4 维数组,

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
>>> data = np.random.randint(0, 5, [4,3,2,3])
>>> data
array([[[[4, 1, 0],
[4, 3, 0]],
[[1, 2, 4],
[2, 2, 3]],
[[4, 3, 3],
[4, 2, 3]]],

[[[4, 0, 1],
[1, 1, 1]],
[[0, 1, 0],
[0, 4, 1]],
[[1, 3, 0],
[0, 3, 0]]],

[[[3, 3, 4],
[0, 1, 0]],
[[1, 2, 3],
[4, 0, 4]],
[[1, 4, 1],
[1, 3, 2]]],

[[[0, 1, 1],
[2, 4, 3]],
[[4, 1, 4],
[1, 4, 1]],
[[0, 1, 0],
[2, 4, 3]]]])

当 axis=0 时,numpy 沿着第 0 维的方向进行求和,也就是第一个元素值 = a0000+a1000+a2000+a3000=11, 第二个元素 = a0001+a1001+a2001+a3001=5,同理可得最后的结果如下:

1
2
3
4
5
6
7
8
9
>>> data.sum(axis=0)
array([[[11, 5, 6],
[ 7, 9, 4]],

[[ 6, 6, 11],
[ 7, 10, 9]],

[[ 6, 11, 4],
[ 7, 12, 8]]])

当 axis=3 时,numpy 沿着第 3 维的方向进行求和,也就是第一个元素值 = a0000+a0001+a0002=5, 第二个元素 = a0010+a0011+a0012=7,同理可得最后的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> data.sum(axis=3)
array([[[ 5, 7],
[ 7, 7],
[10, 9]],

[[ 5, 3],
[ 1, 5],
[ 4, 3]],

[[10, 1],
[ 6, 8],
[ 6, 6]],

[[ 2, 9],
[ 9, 6],
[ 1, 9]]])

Axis 的应用

例如现在我们收集了四个同学对苹果、榴莲、西瓜这三种水果的喜爱程度进行打分的数据(总分为 10),每个同学都有三个特征:

1
2
3
4
5
6
>>> item = np.array([[1,4,8],[2,3,5],[2,5,1],[1,10,7]])
>>> item
array([[1, 4, 8],
[2, 3, 5],
[2, 5, 1],
[1, 10, 7]])

每一行包含了同一个人的三个特征,如果我们想看看哪个同学最喜欢吃水果,那就可以用:

1
2
>>> item.sum(axis = 1)
array([13, 10, 8, 18])

可以大概看出来同学 4 最喜欢吃水果。

如果我们想看看哪种水果最受欢迎,那就可以用:

1
2
>>> item.sum(axis = 0)
array([ 6, 22, 21])

可以看出基本是榴莲最受欢迎。

低维度axis理解

一维数组

对于一维数组,只有一个轴:

  • axis=0:这是唯一的轴,代表数组的唯一维度。

二维数组

二维数组(例如矩阵)有两个轴:

  • axis=0:代表行。对于操作而言,这意味着会==沿着列的方向==进行,即跨越不同的行。
  • axis=1:代表列。操作将沿着行的方向进行,即跨越不同的列。

三维数组

对于三维数组,有三个轴:

  • axis=0:可以想象为不同的==”页”==或”深度层”。
  • axis=1:在给定的页中,沿着”行”的方向。
  • axis=2:在给定的页中,沿着”列”的方向。

以三维数组为例,我们可以将其视为一个数据块,这个数据块由多个二维矩阵(页)堆叠而成。每个”页”是一个二维数组,有其自己的行和列。在这种情况下:

  • axis=0 表示沿着堆叠的方向,或者说是”深度”方向。==操作将跨越不同的页==。
  • axis=1 表示在每个单独的页中,沿着行的方向。这意味着操作将在每页的所有行上进行,但是在同一页内。
  • axis=2 表示在每个单独的页中,沿着列的方向。操作将在每页的所有列上进行,但是在同一页内。

假设我们有一个三维数组 arr,它由 2 个 3x4 的二维数组(页)组成,形状为 (2, 3, 4)。这意味着我们有 2 页,每页 3 行 4 列。

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

# 创建一个三维数组,形状为 (2, 3, 4)
arr = np.array([[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]],

[[13, 14, 15, 16],
[17, 18, 19, 20],
[21, 22, 23, 24]]])

  • 使用 axis=0 对数组进行求和:np.sum(arr, axis=0) 会将两个 3x4 的矩阵对应位置的元素相加,结果是一个 3x4 的矩阵。
  • 使用 axis=1 对数组进行求和:np.sum(arr, axis=1) 对每个二维数组(页)的所有行进行求和,结果是每页一个行向量,形状变为 (2, 4)
  • 使用 axis=2 对数组进行求和:np.sum(arr, axis=2) 对每个二维数组(页)的所有列进行求和,结果是每页一个列向量,形状变为 (2, 3)