用更新运算符进行更新可以不改变数组对象。
代码解析
- 创建空数组
-
y = np.empty((2, 2))
:使用numpy
库的empty
函数创建一个形状为(2, 2)
的空数组y
。这里的 “空” 是指数组元素的值是未初始化的,其值是内存中原来存在的值。
- 对数组元素赋值
-
y[0, 0] = np.sum(x[0, :, 0])
:对y
数组的第0
行第0
列元素赋值。x[0, :, 0]
表示从三维数组x
中取出第0
个二维数组,然后对该二维数组的所有行(:
表示所有行)的第0
列元素进行切片,再使用np.sum
函数对切片后的数组元素求和,并将结果赋值给y[0, 0]
。y[0, 1] = np.sum(x[0, :, 1])
:原理同上,只是对x
数组第0
个二维数组中所有行的第1
列元素求和,并赋值给y
的第0
行第1
列元素。y[1, 0] = np.sum(x[1, :, 0])
:对x
数组第1
个二维数组中所有行的第0
列元素求和,并赋值给y
的第1
行第0
列元素。y[1, 1] = np.sum(x[1, :, 1])
:对x
数组第1
个二维数组中所有行的第1
列元素求和,并赋值给y
的第1
行第1
列元素。
- 输出结果
-
- 最后输出的
array([[ 6., 9.], [24., 27.]])
是经过上述赋值操作后y
数组的最终状态。由于代码中未给出x
数组的定义,这里假设x
是一个三维数组,通过对x
特定切片元素求和得到了y
数组的值。 -
- 最后输出的
代码逐行解释
- 创建并重塑数组
x = np.arange(12).reshape((2, 3, 2))
-
np.arange(12)
:numpy
的arange
函数用于创建一个从0
开始,到11
结束(步长为1
)的一维数组,即[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
。.reshape((2, 3, 2))
:将上述一维数组重塑为一个三维数组,形状为(2, 3, 2)
。可以理解为把这12
个元素按顺序填充到一个2
个 “页” ,每个 “页” 是3
行2
列的三维结构中 。
- 按指定轴求和
np.sum(x, axis=1)
-
np.sum
是numpy
中用于求和的函数。axis=1
表示沿着轴1
进行求和操作。在三维数组x
中,轴0
对应最外层维度(这里是 “页” 的维度,取值0
和1
),轴1
对应中间维度(每个 “页” 中的行维度 ),轴2
对应最内层维度(每个 “页” 中的列维度 )。- 当
axis=1
时,就是对每个 “页” 内的行元素分别求和 。以x
为例,每个 “页” 有3
行,求和后就把行这个维度去掉了,从三维数组(2, 3, 2)
变成了二维数组(2, 2)
,得到最终输出array([[ 6, 9], [24, 27]])
。
具体计算过程示例
假设 x
重塑后的三维数组内容如下(为方便理解,手动划分页、行、列):
第一 “页” :
[[0, 1],
[2, 3],
[4, 5]]
第二 “页” :
[[6, 7],
[8, 9],
[10, 11]]
对第一 “页” 按行求和:
- 第一行
0 + 1 = 1
- 第二行
2 + 3 = 5
- 第三行
4 + 5 = 9
- 总和
1 + 5 + 9 = 6
(这里是第一 “页” 按行求和结果)
对第二 “页” 按行求和: - 第一行
6 + 7 = 13
- 第二行
8 + 9 = 17
- 第三行
10 + 11 = 21
- 总和
13 + 17 + 21 = 24
(这里是第二 “页” 按行求和结果)
最终按列组合起来就是输出的[[ 6, 9], [24, 27]]
。 -
- 下面将更详细地解释这段代码,我们会先回顾相关概念,再结合代码逐行分析,最后给出一个形象的例子来帮助你理解。
相关概念
- 数组维度:可以简单理解为数组的嵌套层数。一维数组就是一个列表,二维数组是列表的列表,三维数组是列表的列表的列表,以此类推。对于二维数组,我们通常把第一个维度称为行,第二个维度称为列。
- 非零元素:在数组中,值不为 0 的元素就是非零元素。
np.nonzero
函数:该函数用于找出数组中非零元素的下标。它会返回一个元组,元组中的每个元素是一个一维数组,这些一维数组分别对应原数组每个维度上非零元素的下标。
代码逐行分析
import numpy as np
# 查找非零元素下标: np.nonzero
# 返回多个array, 每个array是对应维度上的下标
m = np.array([[1, 2], [0, 1]])
x_idx, y_idx = np.nonzero(m)
print(m[x_idx, y_idx])
1. 导入 numpy
库
import numpy as np
这行代码导入了 numpy
库,并将其重命名为 np
,方便后续使用 numpy
中的函数和对象。
2. 创建二维数组 m
m = np.array([[1, 2], [0, 1]])
这里使用 np.array
函数创建了一个二维数组 m
,它的形状是 (2, 2)
,即有 2 行 2 列。数组 m
的具体内容如下:
[[1, 2],
[0, 1]]
3. 使用 np.nonzero
函数查找非零元素的下标
x_idx, y_idx = np.nonzero(m)
np.nonzero(m)
会返回一个元组,元组中有两个一维数组。对于二维数组 m
,第一个一维数组 x_idx
存储的是非零元素在第 0 维(行)上的下标,第二个一维数组 y_idx
存储的是非零元素在第 1 维(列)上的下标。
具体来说,在数组 m
中:
- 元素
1
在第 0 行第 0 列,元素2
在第 0 行第 1 列,元素1
在第 1 行第 1 列。 - 所以
x_idx
为[0, 0, 1]
,表示这三个非零元素分别在第 0 行、第 0 行和第 1 行。 y_idx
为[0, 1, 1]
,表示这三个非零元素分别在第 0 列、第 1 列和第 1 列。
4. 根据下标取出非零元素
print(m[x_idx, y_idx])
这行代码使用 x_idx
和 y_idx
作为索引,从数组 m
中取出对应的非零元素。具体过程如下:
- 首先取
m[0, 0]
,得到元素1
。 - 然后取
m[0, 1]
,得到元素2
。 - 最后取
m[1, 1]
,得到元素1
。
所以最终输出的结果是 [1, 2, 1]
。
形象的例子
假设你有一个 2 行 2 列的教室座位表,座位上可能有人(用非零数字表示),也可能没人(用 0 表示)。这个座位表就可以用数组 m
来表示:
座位表:
| 有人(1) | 有人(2) |
| 没人(0) | 有人(1) |
现在你想找出所有有人的座位的位置。np.nonzero
函数就像是一个“座位查找器”,它会告诉你这些有人的座位分别在第几行和第几列。
x_idx
就是这些有人座位所在的行号,即[0, 0, 1]
。y_idx
就是这些有人座位所在的列号,即[0, 1, 1]
。
最后,通过 m[x_idx, y_idx]
就可以把这些有人座位上的“人”(也就是非零元素)取出来,得到 [1, 2, 1]
。
希望通过以上解释和例子,你能更好地理解这段代码的工作原理。