一、基础索引
Numpy数组索引是一个大话题,有很多方式可以让你选中数据的子集或某个单位元素。一维数组比较简单,看起来和Python的列表类似:
import numpy as np
arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[5]
5
arr[5:8]
array([5, 6, 7])
arr[5:8] = 12
arr
array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
(1)、一维数组
如你所见,如果你传入了一个数值给数组的切片,例如 arr[5:8] = 12,数值被传递给了整个切片。区别于Python的内建列表,数组的切片是原数组的视图。这意味着数据并不是被复制了,任何对于视图的修改都会反映到原数组上。
比如:
arr_1 = arr[5:8]
arr_1
array([12, 12, 12])
当我改变arr_1时,变化也会体现在原数组上:
arr_1[1] =123
arr
array([ 0, 1, 2, 3, 4, 12, 123, 12, 8, 9])
不写切片值[ :]将会引用数组的所有值:
arr_1[:] = 64
arr
array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
如果你还是想要一份数组切片的拷贝而不是一份视图的话,你就必须显式地复制这个数组,例如arr[5:8].copy()
(2)、二维数组
对更高维度的数组,你会有更多选择。在一个二维数组中,每个索引值对应的元素不再是一个值,而是一个一维数组:
arr_2 = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr_2[2]
array([7, 8, 9])
因此,单个元素可以通过递归的方式获得。但是要多写一点代码,你可以通过传递一个索引的逗号分隔列表去选择单个元素,以下两种方式效果一样:
arr_2[0][2]
3
arr_2[0,2]
3
(3)、多维数组
在多维数组中,你可以省略后续索引值,返回的对象将是降低一个维度的数组。因此,在一个2 * 2 * 3的数组arr_3中:
arr_3 = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
arr_3
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr_3[ 0 ]是一个2*3的数组:
arr_3[0]
array([[1, 2, 3],
[4, 5, 6]])
标量和数组都可以传递给arr_3[ 0 ]:
old_values = arr_3[0].copy()
arr_3[0] = 42
arr_3
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
old_values
array([[1, 2, 3],
[4, 5, 6]])
arr_3[0] = old_values
arr_3
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
类似的,arr_3[ 1 ,0]返回的是一个一维数组:
arr_3[1,0]
array([7, 8, 9])
当然上面的表达式也可以分解为下面两步:
x = arr_3[1]
x
array([[ 7, 8, 9],
[10, 11, 12]])
x[0]
array([7, 8, 9])
需要注意的是,以上的数组子集选择中,返回的数组都是视图
二、切片索引
与Python列表的一维对象类似,数组可以通过类似的语法进行切片:
arr
array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
arr[1:6]
array([ 1, 2, 3, 4, 64])
在二维数组中,对数组进行切片又略有不同:
arr_2
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
arr_2[:2]
array([[1, 2, 3],
[4, 5, 6]])
如你所见,数组沿着轴0进行了切片。表达式arr_[ :2]的含义为选择arr_2的前俩行。
你可以进行多组切片,与多组索引类似:
arr_2[:2,1:]
array([[2, 3],
[5, 6]])
当你像在上面这个例子中那样切片时,你需要按照原数组的维度进行切片。如果将索引和切片混合,就可以得到低维度的切片。
例如,我可以下载第二行但是只是选择前两列:
arr_2[1,:2]
array([4, 5])
类似的,我也可以选择第三列,但是只是选择前两行:
arr_2[:2,2]
array([3, 6])
当然,需要注意的是,单独一个冒号表示选择整个轴上的数组,因此你可以按照下面的方式在更高维度上进行切片:
arr_2[:,:1]
array([[1],
[4],
[7]])
当然对切片表达式赋值时,整个切片都会出现赋值:
arr_2[:2,1:] = 0
arr_2
array([[1, 0, 0],
[4, 0, 0],
[7, 8, 9]])
数组的切片方式千变万化,对于新手来说只要能找到自己想要的数据就是最合适的。