跳到主要内容

Numpy 的索引与切片

Python 的内置容器对象,例如列表,可以通过索引或切片来访问和修改。这在 ndarray 对象中也一样,ndarray 对象中的元素遵循基于零的索引,常用的索引方式:元素访问、切片索引、布尔型索引。

1. 元素访问

1.1 单一元素访问

一维数组的元素访问非常简单,和 Python 列表规则基本差不多。对单一元素的访问,索引遵循从 0 开始,依次递增 1。

案例

例如,对于创建的一维数组,我们访问第5个元素对象:

arr = np.arange(10)

arr
Out:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

arr[4]
Out:
4

也可以用负数从末位开始对数组反向索引,例如-1表示末位元素:

arr[-1]
Out:
9

2. 切片索引

2.1 基本切片

跟列表类似,你可以一次性多个索引位置,进行多元素的访问。如果索引位置是离散的,可以手动构造列表切片的形式传入。也可以利用 start、stop、step 的方式来生成切片器。

案例

对于上述创建的一位数组,我们同时访问首尾的元素,那么可以指定其索引位置0和-1,语法如下:

arr[[0, -1]]
Out:
array([0, 9])

这种情况下,访问结果会重新构造为ndarray对象返回。

对于有规律的访问,可以构造相应的切片器,例如我们访问上述数组中的偶数元素:

arr[0: -1: 2]
Out:
array([0, 2, 4, 6, 8])

需要注意的是,在上述构造的切片器中,最后一位索引序列是无法取到的。例如我们访问奇数元素:

arr[1: -1: 2]
Out:
array([1, 3, 5, 7])

arr[1: : 2]
Out:
array([1, 3, 5, 7, 9])

对比发现,当切片器指定了 -1 时,末位元素是不会被选中的。

2.2 多维数组切片索引

对于二维数组,在某些特殊情况下,可以通过连续切片的方式进行访问。

案例

例如,我们创建一个连续整数组成的方阵:

arr_2d = np.arange(16).reshape(4,4)
Out:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])

arr_2d 构造一个连续切片:

arr_2d[0][1:3]
Out:
array([1, 2])

对多维数组的索引,想要达到同样的的效果,可以一次传入多个切片。例如对上述结果,可以修改为:

arr_2d[0, 1:3]
Out:
array([1, 2])

在上述步骤中,传入了 2 个切片。严格来讲,第一个切片是整数索引,是对数组的最外层(axis=0)进行选择;第二个切片是对数组的内一层(axis=1)进行选择。

更一般地,我们可以自由地根据需求,构造想要的切片效果。例如:

arr_2d[0:2, 1:3]
Out:
array([[1, 2],
[5, 6]])

上述案例在 axis=0 方向上选择了第 0 和第 1 行,在 axis=1 方向上选择了第 1 列和第 2 列,两种切片方向的聚焦部分即为切片索引的结果。

需要指出的是,如果切片只有冒号,表示选取该方向的整个轴。例如,利用该方法,可以对二维数组进行列方向的切片:

arr_2d[:, 1:3]
Out:
array([[ 1, 2],
[ 5, 6],
[ 9, 10],
[13, 14]])

上述案例实现了选择第一列和第二列的效果。

3. 布尔型索引

直观上理解,通过布尔类型来完成索引的过程,我们可以称之为布尔型索引。

案例

例如对于上述 arr_2d,我们通过传入 [True, True, False, False] 这样一个布尔类型的列表,来选择第 0 行和第 1 行:

arr_2d[[True, True, False, False]]
Out:
array([[0, 1, 2, 3],
[4, 5, 6, 7]])

需要注意的是,传入的布尔类型列表的长度,需要跟被索引的轴的长度一致,否则会引起 IndexError。在实际使用中,可以灵活地把布尔索引和切片索引、整数索引混合使用,非常方便。

例如,这里利用布尔型索引和切片索引来达到列方向切片的效果:

arr_2d[:, [True, True, False, False]]
Out:
array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]])

4. 小结