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