- Python科学计算(第2版)
- 张若愚
- 912字
- 2025-03-09 06:39:30
2.3.2 整数数组作为下标
下面看看下标元组中的元素由切片和整数数组构成的情况。假设整数数组有Nt个,而切片有Ns个。Nt +Ns为数组的维数D。
首先,这Nt个整数数组必须满足广播条件,假设它们进行广播之后的维数为M,形状为(d0,d1,…,dM-1)。
如果Ns为0,即没有切片元素时,则下标所得到的结果数组result的形状和整数数组广播之后的形状相同。它的每个元素值按照下面的公式获得:

其中,ind0到indnt -1为进行广播之后的整数数组。让我们看一个例子,从而加深对此公式的理解:
若只需要沿着指定轴通过整数数组获取元素,可以使用numpy.take()函数,其运算速度比整数数组的下标运算略快,并且支持下标越界处理。
i0 = np.array([[1, 2, 1], [0, 1, 0]]) i1 = np.array([[[0]], [[1]]]) i2 = np.array([[[2, 3, 2]]]) b = a[i0, i1, i2] b array([[[22, 43, 22], [ 2, 23, 2]], [[27, 48, 27], [ 7, 28, 7]]])
首先,i0、i1、i2三个整数数组的shape属性分别为(2,3)、(2,1,1)、(1,1,3)。根据广播规则,先在长度不足3的shape属性前面补1,使得它们的维数相同,广播之后的shape属性为各个轴的最大值:
(1, 2, 3) (2, 1, 1) (1, 1, 3) --------- 2 2 3
即三个整数数组广播之后的shape属性为(2,2,3),这也就是下标运算所得到的结果数组的维数:
b.shape (2, 2, 3)
我们可以使用broadcast_arrays()查看广播之后的数组:

对于b中的任意一个元素b[i,j,k],它是数组a中经过ind0、ind1和ind2进行下标转换之后的值:
i, j, k = 0, 1, 2 print b[i, j, k], a[ind0[i, j, k], ind1[i, j, k], ind2[i, j, k]] i, j, k = 1, 1, 1 print b[i, j, k], a[ind0[i, j, k], ind1[i, j, k], ind2[i, j, k]] 2 2 28 28
下面考虑Ns不为0的情况。当存在切片下标时,情况就变得更加复杂了。可以细分为两种情况:下标元组中的整数数组之间没有切片,即整数数组只有一个或连续的多个整数数组。这时结果数组的shape属性为:将原始数组的shape属性中整数数组所占据的部分替换为它们广播之后的shape属性。例如假设原始数组a的shape属性为(3,4,5),i0和i1广播之后的形状为(2,2,3),则a[1:3,i0,i1]的形状为(2,2,2,3):
c = a[1:3, i0, i1] c.shape (2, 2, 2, 3)
其中,c的shape属性中的第一个2是切片“1:3”的长度,后面的(2,2,3)则是i0和i1广播之后的数组的形状:
ind0, ind1 = np.broadcast_arrays(i0, i1) ind0.shape (2, 2, 3)
i, j, k = 1, 1, 2 print c[:, i, j, k] print a[1:3, ind0[i, j, k], ind1[i, j, k]] # 和c[:,i,j,k]的值相同 [21 41] [21 41]
当下标元组中的整数数组不连续时,结果数组的shape属性为整数数组广播之后的形状后面添加上切片元素所对应的形状。例如a[i0,:,i1]的shape属性为(2,2,3,4),其中(2,2,3)是i0和i1广播之后的形状,而4是数组a的第1轴的长度:
d = a[i0, :, i1] d.shape (2, 2, 3, 4)
i, j, k = 1, 1, 2 d[i,j,k,:] a[ind0[i,j,k],:,ind1[i,j,k]] ---------------- ---------------------------- [ 1, 6, 11, 16] [ 1, 6, 11, 16]