菜单
本页目录

多维数组

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]])

示例操作:

  1. 获取第0行,索引3到4的元素:
a[0, 3:5]

输出:

array([3, 4])
  1. 获取第4行及以后的元素,索引为4及其以后的元素:
a[4:, 4:]

输出:

array([[44, 45],
       [54, 55]])
  1. 获取从第2行开始,每隔2行获取一次,列索引为偶数的元素:
a[2::2, ::2]

输出:

array([[20, 22, 24],
       [40, 42, 44]])
0ed5d5856b8f4fa903f5ac485ae0085.png
NOTE

上面这些切片操作都是对原数组的共享储存空间。即,它们不会创立新的副本,而是指向相同的存储区域。


2. 创建数组的副本

如果我们希望创立数组的副本,可以使用整数元组列表整数数组布尔数组进行切片。示例如下:

  1. 使用整数元组切片:
a[(0, 1, 2, 3, 4), (1, 2, 3, 4, 5)]

输出:

# 图片中橙色区域
array([ 1, 12, 23, 34, 45])
  1. 使用列表切片:
a[3:, [0, 2, 5]]

输出:

# 图片蓝色区域
array([[30, 32, 35],
       [40, 42, 45],
       [50, 52, 55]])
  1. 使用布尔数组切片:
# 创建布尔数组,选择行
mask = np.array([True, False, True, False, False, True], dtype=bool)

# 使用布尔数组切片,选出行并在第二列上进行选择
result = a[mask, 2]
print(result)

输出:

# 图片红色区域
array([ 2, 22, 52])
20240910134656.png

3. 解析一下二维数组生成代码

以下代码段 a = np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6) 创建了一个二维数组,具体步骤如下:

  1. np.arange(0, 60, 10):生成一维数组
  • np.arange(0, 60, 10) 生成一个从 060 之间的数组,步长为 10,因此得到的是:
array([ 0, 10, 20, 30, 40, 50])

这个数组是一维的。

  1. .reshape(-1, 1):将一维数组转为列向量
  • .reshape(-1, 1) 将一维数组转为一个二维的列向量。-1 表示根据另一维度的大小自动计算行数,而 1 表示将数组转为一列。因此,生成的列向量是:
array([[ 0],
       [10],
       [20],
       [30],
       [40],
       [50]])

现在这是一个6行1列的二维数组。

  1. np.arange(0, 6):生成行向量
  • np.arange(0, 6) 生成一个从 05 的一维数组:
array([0, 1, 2, 3, 4, 5])
  1. 列向量与行向量相加
  • 当一个列向量与一个行向量相加时,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. 广播机制解析

  1. 初始数组
  • 列向量(形状为 (6, 1)):
array([[ 0],
       [10],
       [20],
       [30],
       [40],
       [50]])
  • 行向量(形状为 (6,)):
array([0, 1, 2, 3, 4, 5])
  1. 广播机制

NumPy 的广播规则是:

  1. 如果两个数组的维度不同,先通过在较小数组的前面加上 1 来使它们的维度相同。
  2. 对于每个维度,如果其中一个数组在该维度的大小为 1,那么它会被扩展为与另一个数组在该维度的大小相同。

在你的例子中,广播的具体过程如下:

  1. 对齐维度:
  • 列向量的形状是 (6, 1),行向量的形状是 (6,)
  • NumPy 会把行向量的形状自动调整为 (1, 6) 以便与列向量对齐:
array([[0, 1, 2, 3, 4, 5]])  # 现在形状为 (1, 6)
  1. 广播扩展:
  • 列向量的形状为 (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]])
  1. 逐元素相加
  • 将两个形状为 (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]])
  1. 最终结果 最后得到的二维数组为:
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]])