神奇索引是Numpy中的术语,用于描述使用整数数组进行数据索引。
假设我们有一个8 * 4的数组:
import numpy as np
arr = np.empty((8,4))
for i in range(8):
arr[i] = i
arr
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
为了选出一个符合特定顺序的子集,你可以简单地通过传递一个包含指明所需顺序的列表或数组来完成:
arr[[4,3,0,6]]
arr[[4,3,0,6]]
arr[[4,3,0,6]]
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
代码运行出你所想要的结果 !如果使用负的索引,将从尾部进行选择:
arr[[-3,-5,-7]]
array([[5., 5., 5., 5.],
[3., 3., 3., 3.],
[1., 1., 1., 1.]])
传递多个索引数组时情况有些不同,这样会根据每个索引元组对应的元素选出一个一维数组:
arr = np.arange(32).reshape((8,4))
arr
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]])
arr[[1,5,7,2],[0,3,1,2]]
array([ 4, 23, 29, 10])
在上述例子中,元素(1,0)、(5,3)、(7,1)和(2,2)被选中。如果不考虑数组的整数,神奇索引的结果总是一维的。
通常情况下,我们所设想的结果是通过选择矩阵中行列的子集所形成的矩形区域。下面是实现我们想法的一种方式:
arr[[1,5,7,2]][:,[0,3,1,2]]
arr[[1,5,7,2]][:,[0,3,1,2]]
arr[[1,5,7,2]][:,[0,3,1,2]]
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
请牢记神奇索引与切片不同,它总是将数据复制到一个新的数组中。
使用整数数组通过神奇索引是获取、设置数组子集的一种方式:
arr = np.arange(10)*100
inds = [7,1,2,6]
arr[inds]
array([700, 100, 200, 600])
还有其他一些ndarray方法可以用于特殊情况下在单个轴上的数据选取:
arr.take(inds)
array([700, 100, 200, 600])
arr.put(inds,42)
arrarr
array([ 0, 42, 42, 300, 400, 500, 42, 42, 800, 900])
arr.put(inds,[40,41,42,43])
arr
array([ 0, 41, 42, 300, 400, 500, 43, 40, 800, 900])
如果要在别的轴上使用take,你可以传递axis关键字:
inds = [2,0,2,1]
arr = np.random.randn(2,4)
arr
array([[-0.47852409, 1.5660483 , -0.39136069, 1.61344622],
[ 0.96982202, -0.03322147, -1.50562567, 2.09119665]])
arr.take(inds,axis =1)
array([[-0.39136069, -0.47852409, -0.39136069, 1.5660483 ],
[-1.50562567, 0.96982202, -1.50562567, -0.03322147]])
put不接受axis参数,而是将数组索引到扁平版本。因此,当你需要使用其他轴上的索引数组设置元素时,通常最容易使用神奇索引。