多维数组
1. 获取多维度数组的切片
NumPy的多维数组与一维数组类似。多维数组有多个轴,轴的编号从内到外依次为第0轴,第1轴等。
下面是一个例子:
import numpy as np
a = np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6)
print(a)
输出:
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
示例操作:
- 获取第0行,索引3到4的元素:
a[0, 3:5]
输出:
array([3, 4])
- 获取第4行及以后的元素,索引为4及其以后的元素:
a[4:, 4:]
输出:
array([[44, 45],
[54, 55]])
- 获取从第2行开始,每隔2行获取一次,列索引为偶数的元素:
a[2::2, ::2]
输出:
array([[20, 22, 24],
[40, 42, 44]])

上面这些切片操作都是对原数组的共享储存空间。即,它们不会创立新的副本,而是指向相同的存储区域。
2. 创建数组的副本
如果我们希望创立数组的副本,可以使用整数元组、列表、整数数组或布尔数组进行切片。示例如下:
- 使用整数元组切片:
a[(0, 1, 2, 3, 4), (1, 2, 3, 4, 5)]
输出:
# 图片中橙色区域
array([ 1, 12, 23, 34, 45])
- 使用列表切片:
a[3:, [0, 2, 5]]
输出:
# 图片蓝色区域
array([[30, 32, 35],
[40, 42, 45],
[50, 52, 55]])
- 使用布尔数组切片:
# 创建布尔数组,选择行
mask = np.array([True, False, True, False, False, True], dtype=bool)
# 使用布尔数组切片,选出行并在第二列上进行选择
result = a[mask, 2]
print(result)
输出:
# 图片红色区域
array([ 2, 22, 52])

3. 解析一下二维数组生成代码
以下代码段 a = np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6)
创建了一个二维数组,具体步骤如下:
np.arange(0, 60, 10)
:生成一维数组
np.arange(0, 60, 10)
生成一个从0
到60
之间的数组,步长为10
,因此得到的是:
array([ 0, 10, 20, 30, 40, 50])
这个数组是一维的。
.reshape(-1, 1)
:将一维数组转为列向量
.reshape(-1, 1)
将一维数组转为一个二维的列向量。-1
表示根据另一维度的大小自动计算行数,而1
表示将数组转为一列。因此,生成的列向量是:
array([[ 0],
[10],
[20],
[30],
[40],
[50]])
现在这是一个6行1列的二维数组。
np.arange(0, 6)
:生成行向量
np.arange(0, 6)
生成一个从0
到5
的一维数组:
array([0, 1, 2, 3, 4, 5])
- 列向量与行向量相加
- 当一个列向量与一个行向量相加时,NumPy会进行广播(broadcasting)操作。广播机制自动扩展较小维度的数组,使得它们可以进行逐元素操作。
- 列向量的形状是
(6, 1)
,行向量的形状是(6,)
,通过广播,行向量会扩展成(6, 6)
,每一行的值相同,然后进行逐元素相加。
- 列向量的形状是
结果是一个 (6, 6)
的二维数组:
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
4. 广播机制解析
- 初始数组
- 列向量(形状为
(6, 1)
):
array([[ 0],
[10],
[20],
[30],
[40],
[50]])
- 行向量(形状为
(6,)
):
array([0, 1, 2, 3, 4, 5])
- 广播机制
NumPy 的广播规则是:
- 如果两个数组的维度不同,先通过在较小数组的前面加上
1
来使它们的维度相同。 - 对于每个维度,如果其中一个数组在该维度的大小为
1
,那么它会被扩展为与另一个数组在该维度的大小相同。
在你的例子中,广播的具体过程如下:
- 对齐维度:
- 列向量的形状是
(6, 1)
,行向量的形状是(6,)
。 - NumPy 会把行向量的形状自动调整为
(1, 6)
以便与列向量对齐:
array([[0, 1, 2, 3, 4, 5]]) # 现在形状为 (1, 6)
- 广播扩展:
- 列向量的形状为
(6, 1)
,行向量现在被看作是(1, 6)
,通过广播机制,两个数组将扩展为相同的形状(6, 6)
。 - 行向量会在第0轴上进行扩展,变成下面的数组
b
:
b = array([[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]])
而列向量本身已经是 (6, 1)
,所以只需在第1轴上扩展:
array([[ 0],
[10],
[20],
[30],
[40],
[50]])
- 逐元素相加
- 将两个形状为
(6, 6)
的数组逐元素相加:
array([[ 0], array([[0, 1, 2, 3, 4, 5], array([[ 0, 1, 2, 3, 4, 5],
[10], + [0, 1, 2, 3, 4, 5], = [10, 11, 12, 13, 14, 15],
[20], [0, 1, 2, 3, 4, 5], [20, 21, 22, 23, 24, 25],
[30], [0, 1, 2, 3, 4, 5], [30, 31, 32, 33, 34, 35],
[40], [0, 1, 2, 3, 4, 5], [40, 41, 42, 43, 44, 45],
[50]]) [0, 1, 2, 3, 4, 5]]) [50, 51, 52, 53, 54, 55]])
- 最终结果 最后得到的二维数组为:
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])