Numpy数组的索引是一个内容丰富的主题,因为选取数据子集和单个元素的方式有很多。一维数组很简单。从表面上看,它们跟Python列表的功能差不多:
In [109]: arr=np.arange(10)
In [110]: arr
Out[110]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [111]: arr[5]
Out[111]: 5
In [112]: arr[5:8]
Out[112]: array([5, 6, 7])
In [113]: arr[5:8]=12
In [114]: arr
Out[114]: array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
如上所示,当你将一个标量赋值给一个切片时(如arr[5;8]=12),该值会自动广播到整个选区。跟列表最重要的区别在于,数组切片是原始数组的视图。这意味着数据不会被复制,视图上的任何修改都会直接反映到原数组上:
In [117]: arr_slice=arr[5:8]
In [118]: arr_slice[1]=12345
In [119]: arr
Out[119]: array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8,
9])
In [120]: arr_slice[:]=64
In [121]: arr
Out[121]: array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
如果你刚开始接触Python,可能会对此感到惊讶(尤其是当你曾经用过其他热衷于复制数组数据的语言)。由于Numpy的设计目的是处理大数据,所以你可以想象一下,假如Numpy坚持要将数据复制来复制去的话会产生何等性能和内存问题。
当然,如果你想要得到的是ndarray切片的一份副本而非视图,就需要显示地进行复制操作,例如arr[5:8].copy()。
对于高维数组,能做的事情更多。在一个二维数组中,各索引位置上的元素不再是标量而是一维数组:
In [122]: arr2d=np.array([[1,2,3],[4,5,6],[7,8,9]])
In [123]: arr2d[2]
Out[123]: array([7, 8, 9])
因此,可以对各个元素进行递归访问,但这样需要做的事情有点多。你可以传入一个以逗号隔开的索引列表来选取单个元素。也就是说,下面两种方式是等价的:
In [124]: arr2d[0][2]
Out[124]: 3
In [125]: arr2d[0,2]
Out[125]: 3
在多维数组中,如果省略了后面的索引,则返回对象会是一个维度低一点的ndarray。因此,在2*2*3数组arr3d中:
In [126]: arr3d=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
In [127]: arr3d
Out[127]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr3d[0]是一个2*3数组:
In [128]: arr3d[0]
Out[128]:
array([[1, 2, 3],
[4, 5, 6]])
标量值和数组都可以被赋值给arr3d[0]:
In [129]: old_values=arr3d[0].copy()
In [130]: arr3d[0]=42
In [131]: arr3d
Out[131]:
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [132]: arr3d[0]=old_values
In [133]: arr3d
Out[133]:
array([[[ 1, 2, 3],