高级索引

Numpy 比一般的 Python 序列提供更多的索引方式。除了前面章节介绍的用整数和切片的索引外,本节深入介绍布尔型索引和花式索引。

1. 布尔型索引

在前面的章节,我们简单介绍了,可以通过一个布尔数组来索引目标数组。

1.1 比较运算符与布尔型数组

在实际使用中,可以通过比较运算符来产生一个布尔型数组。

案例

利用random模块产生一个大小为7×4的随机数数组:

data = np.random.randn(7,4)
data
out:
    array([[-0.79578969, -0.73156773,  0.60648318, -0.57213653],
       [ 0.03461754, -0.91921724, -1.51730244,  0.68583205],
       [-0.0584198 , -0.92494003, -0.08106442, -1.44821654],
       [-0.76501214,  2.01128245,  1.0350961 ,  0.81014769],
       [-0.71850433, -1.613115  , -0.23420344,  0.61378525],
       [-1.06667762,  1.11845542,  1.68075202,  0.25989931],
       [-0.80773979, -0.37137009,  0.45941405, -0.57604566]])

定义一个名称数组,长度为7,并假设上述data中的每一行与名称数组中的名字一一对应。

names = np.array(['Ben','Tom','Ben','Jeremy','Jeremy','Tom','Ben'])
names
out:
    array(['Ben', 'Tom', 'Ben', 'Jeremy', 'Jeremy', 'Tom', 'Ben'], dtype='<U6')

对data数组,通过传入一个比较运算符,可以与全部元素逐一比较:

data > 0
out:
    array([[False, False,  True, False],
       [ True, False, False,  True],
       [False, False, False, False],
       [False,  True,  True,  True],
       [False, False, False,  True],
       [False,  True,  True,  True],
       [False, False,  True, False]])

对同样大小的布尔型数组,可以利用&(和)、|(或)、-(非)进行运算。

例如对data进行-1~1之间的判断:

(data>-1) & (data < 1)
out:
    array([[ True,  True,  True,  True],
       [ True,  True, False,  True],
       [ True,  True,  True, False],
       [ True, False, False,  True],
       [ True, False,  True,  True],
       [False, False, False,  True],
       [ True,  True,  True,  True]])

1.2 比较运算符与布尔型索引

先利用比较运算符创建布尔型数组,再利用布尔型索引的功能,可以快速进行筛选。

案例

names中的每一个名字,和data的每一行是一一对应的关系。因此可以快速地选择出Ben的相关信息:

data[names=='Ben']
out:
    array([[-0.79578969, -0.73156773,  0.60648318, -0.57213653],
       [-0.0584198 , -0.92494003, -0.08106442, -1.44821654],
       [-0.80773979, -0.37137009,  0.45941405, -0.57604566]])

利用‘&’运算符,一次性选择出Ben和Tom的相关信息

data[(names=='Ben') | (names=='Tom')]
out:
    array([[-0.79578969, -0.73156773,  0.60648318, -0.57213653],
       [ 0.03461754, -0.91921724, -1.51730244,  0.68583205],
       [-0.0584198 , -0.92494003, -0.08106442, -1.44821654],
       [-1.06667762,  1.11845542,  1.68075202,  0.25989931],
       [-0.80773979, -0.37137009,  0.45941405, -0.57604566]])

布尔型数组也可以和切片、整数索引混合使用:

array([[-0.79578969, -0.73156773],
       [ 0.03461754, -0.91921724],
       [-0.0584198 , -0.92494003],
       [-1.06667762,  1.11845542],
       [-0.80773979, -0.37137009]])

特别地,也可以利用data本身,快速选择出大于0的元素:

data[data > 0]
out:
    array([0.60648318, 0.03461754, 0.68583205, 2.01128245, 1.0350961 ,
       0.81014769, 0.61378525, 1.11845542, 1.68075202, 0.25989931,
       0.45941405])

这里选择的结果是以一维数组的形式返回的。

2. 花式索引

花式索引是一个Numpy术语,是指利用整数数组进行索引。

2.1 使用一维整型数组作为索引

对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。

案例

对于上述案例中的names数组,通过传入一个特定顺序的整数列表(或ndarray),来按照指定顺序选取元素:

names[[4,3,2,1]]
out:
    array(['Jeremy', 'Jeremy', 'Ben', 'Tom'], dtype='<U6')

如果使用负数,则会从末尾开始选取:

names[[-1,-2,-3,-4]]
out:
    array(['Ben', 'Tom', 'Jeremy', 'Jeremy'], dtype='<U6')

案例

同样地,对data二维数组,通过传入特定顺序的整数列表,来按照指定顺序选取行:

data[[3,1]]
out:
    array([[-0.76501214,  2.01128245,  1.0350961 ,  0.81014769],
       [ 0.03461754, -0.91921724, -1.51730244,  0.68583205]])

2.2 传入多组索引序列

一次性传入多个索引数组,这种情况会有一些特殊,其返回的是一个一维数组,其中的元素对应各个索引元祖。

案例

data[[3,1,2],[0,2,1]]
out:
    array([-0.76501214, -1.51730244, -0.92494003])

一次性传入两个列表:[3,1,2]、[0,2,1],最终选取出三个元素,其在data数组中的位置分别是(3, 0)、(1, 2)、(2, 1)。并没有和切片索引一样,返回一个矩形区域。

那么如何能够索引矩形区域呢?

案例

下面是得到矩形区域的一个这种的办法:

data[[3,1,2]][:,[0,2,1]]
out:
    array([[-0.76501214,  1.0350961 ,  2.01128245],
       [ 0.03461754, -1.51730244, -0.91921724],
       [-0.0584198 , -0.08106442, -0.92494003]])

另外,需要记住一个结论是:花式索引和切片不一样,它总是将数据复制到一个新的数组中。

3. 小结

本节介绍了两种较为复杂的索引:布尔型索引和花式索引。布尔型索引中,通过与比较运算符连用,可以快速基于判断逻辑,筛选出指定数据。花式索引则是一种应用不多,但是较为特殊的索引,需要了解。