基本索引
ndarray
对象的内容可以通过索引或切片来访问和修改,就像 Python 的内置容器对象一样。
如前所述,ndarray
对象中的元素遵循基于零的索引。 有三种可用的索引方法类型: 字段访问,基本切片和高级索引。
基本切片是 Python 中基本切片概念到 n 维的扩展。 通过将start
,stop
和step
参数提供给内置的slice
函数来构造一个 Python slice
对象。 此slice
对象被传递给数组来提取数组的一部分。
示例
>>> np.arange(10)[slice(2, 7, 2)]
array([2, 4, 6])
>>> np.arange(10)[0]
0
>>> np.arange(10)[:]
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.arange(10)[2:7]
array([2, 3, 4, 5, 6])
>>> a = np.array([[1,2,3],[3,4,5],[4,5,6]])
>>> a[1]
array([3, 4, 5])
>>> a[2, ...]
array([4, 5, 6])
在上面的例子中,
ndarray
对象由arange()
函数创建。 然后,分别用起始,终止和步长值2
,7
和2
定义切片对象。 当这个切片对象传递给ndarray
时,会对它的一部分进行切片,从索引2
到7
,步长为2
。通过将由冒号分隔的切片参数(
start:stop:step
)直接提供给ndarray
对象,也可以获得相同的结果。如果只输入一个参数,则将返回与索引对应的单个项目。 如果使用
a[:]
,则从该索引向后的所有项目将被提取。 如果使用两个参数(以:
分隔),则对两个索引之间的元素以默认步骤进行切片。上面的描述也可用于多维
ndarray
。切片还可以包括省略号(
...
),来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的ndarray
。
高级索引
如果一个ndarray
是非元组序列,数据类型为整数或布尔值的ndarray
,或者至少一个元素为序列对象的元组,我们就能够用它来索引ndarray
。高级索引始终返回数据的副本。 与此相反,切片只提供了一个视图。
有两种类型的高级索引:整数和布尔值。
整数索引
这种机制有助于基于 N
维索引来获取数组中任意元素。 每个整数数组表示该维度的下标值。 当索引的元素个数就是目标ndarray
的维度时,会变得相当直接。
以下示例获取了ndarray
对象中每一行指定列的一个元素。 因此,行索引包含所有行号,列索引指定要选择的元素。
示例 1
>>> np.array([[1, 2], [3, 4], [5, 6]])[[0, 1, 2], [0, 1, 0]]
array([1, 4, 5])
该结果包括数组中(0,0)
,(1,1)
和(2,0)
位置处的元素。
下面的示例获取了 4X3 数组中的每个角处的元素。 行索引是[0,0]
和[3,3]
,而列索引是[0,2]
和[0,2]
。
示例 2
>>> x
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
>>> row = np.array([[0, 0], [3, 3]])
>>> col = np.array([[0, 2], [0, 2]])
>>> x[row, col]
array([[ 0, 2],
[ 9, 11]])
返回的结果是包含每个角元素的ndarray
对象。
高级和基本索引可以通过使用切片:
或省略号...
与索引数组组合。 以下示例使用slice
作为列索引和高级索引。 当切片用于两者时,结果是相同的。 但高级索引会导致复制,并且可能有不同的内存布局。
示例 3
>>> x = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
>>> x
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
>>> x[1:4, 1:3]
array([[ 4, 5],
[ 7, 8],
[10, 11]])
>>> x[1:4, [1, 2]]
array([[ 4, 5],
[ 7, 8],
[10, 11]])
布尔索引
当结果对象是布尔运算(例如比较运算符)的结果时,将使用此类型的高级索引。
示例 1
这个例子中,大于 5 的元素会作为布尔索引的结果返回。
>>> x = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
>>> x[x>5]
array([ 6, 7, 8, 9, 10, 11])
示例 2
这个例子使用了~
(取补运算符)来过滤NaN
。
>>> a = np.array([np.nan,1,2,np.nan,3,4,5])
>>> a[~np.isnan(a)]
array([1., 2., 3., 4., 5.])
示例 3
以下示例显示如何从数组中过滤掉非复数元素。
>>> a = np.array([1,2+6j,5,3.5+5j])
>>> a[np.iscomplex(a)]
array([2. +6.j, 3.5+5.j])
多维数组
多维数组的存取和一维数组类似,因为多维数组有多个轴,因此它的下标需要用多个值来表示,NumPy采用组元(tuple)作为数组的下标。组元不需要圆括号,虽然经常在Python中用圆括号将组元括起来,但是其实组元的语法定义只需要用逗号隔开即可,例如 x,y=y,x 就是用组元交换变量值的一个例子。
使用数组切片语法访问多维数组中的元素
如何创建这个数组
你也许会对如何创建a这样的数组感到好奇,数组a实际上是一个加法表,纵轴的值为0, 10, 20, 30, 40, 50;横轴的值为0, 1, 2, 3, 4, 5。纵轴的每个元素都和横轴的每个元素求和,就得到图中所示的数组a。你可以用下面的语句创建它,至于其原理我们将在后面的章节进行讨论:
>>> np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6)
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
多维数组同样也可以使用整数序列和布尔数组进行存取。
使用整数序列和布尔数组访问多维数组中的元素
a[(0,1,2,3,4),(1,2,3,4,5)] : 用于存取数组的下标和仍然是一个有两个元素的组元,组元中的每个元素都是整数序列,分别对应数组的第0轴和第1轴。从两个序列的对应位置取出两个整数组成下标: a[0,1], a[1,2], ..., a[4,5]。
a[3:, [0, 2, 5]] : 下标中的第0轴是一个范围,它选取第3行之后的所有行;第1轴是整数序列,它选取第0, 2, 5三列。
a[mask, 2] : 下标的第0轴是一个布尔数组,它选取第0,2,5行;第1轴是一个整数,选取第2列。
where
使用 where 函数能将索引掩码转换成索引位置:
>>> np.where([[True, False], [True, True]],
... [[1, 2], [3, 4]],
... [[9, 8], [7, 6]])
array([[1, 8],
[3, 4]])
>>> np.where([[0, 1], [1, 0]])
(array([0, 1]), array([1, 0]))
>>> x = np.arange(9.).reshape(3, 3)
>>> np.where( x > 5 )
(array([2, 2, 2]), array([0, 1, 2]))
>>> x[np.where( x > 3.0 )] # Note: result is 1D.
array([ 4., 5., 6., 7., 8.])
>>> np.where(x < 5, x, -1) # Note: broadcasting.
array([[ 0., 1., 2.],
[ 3., 4., -1.],
[-1., -1., -1.]])
>>> # Find the indices of elements of `x` that are in `goodvalues`.
>>> goodvalues = [3, 4, 7]
>>> ix = np.isin(x, goodvalues)
>>> ix
array([[False, False, False],
[ True, True, False],
[False, True, False]])
>>> np.where(ix)
(array([1, 1, 2]), array([0, 1, 1]))
take
take
函数与高级索引(fancy indexing)用法相似:
>>> a = [4, 3, 5, 7, 6, 8]
>>> indices = [0, 1, 4]
>>> np.take(a, indices)
array([4, 3, 6])
>>> # In this example if `a` is an ndarray, "fancy" indexing can be used.
>>> a = np.array(a)
>>> a[indices]
array([4, 3, 6])
>>> # If `indices` is not one dimensional, the output also has these dimensions.
>>> np.take(a, [[0, 1], [2, 3]])
array([[4, 3],
[5, 7]])
但是 take
也可以用在 list 和其它对象上:
choose
选取多个数组的部分组成新的数组:
>>> choices = [[0, 1, 2, 3], [10, 11, 12, 13],
... [20, 21, 22, 23], [30, 31, 32, 33]]
>>> np.choose([2, 3, 1, 0], choices
... # the first element of the result will be the first element of the
... # third (2+1) "array" in choices, namely, 20; the second element
... # will be the second element of the fourth (3+1) choice array, i.e.,
... # 31, etc.
... )
array([20, 31, 12, 3])
>>> np.choose([2, 4, 1, 0], choices, mode='clip') # 4 goes to 3 (4-1)
array([20, 31, 12, 3])
>>> # because there are 4 choice arrays
>>> np.choose([2, 4, 1, 0], choices, mode='wrap') # 4 goes to (4 mod 4)
array([20, 1, 12, 3])
>>> # i.e., 0
>>> # A couple examples illustrating how choose broadcasts:
>>> a = [[1, 0, 1], [0, 1, 0], [1, 0, 1]]
>>> choices = [-10, 10]
>>> np.choose(a, choices)
array([[ 10, -10, 10],