也可以看看
ndarrays
可以使用标准Python x[obj]
语法建立索引
,其中x是数组,而obj是选择。有三种索引可用:字段访问,基本切片,高级索引。哪一个发生取决于obj。
注意
在Python中,相当于
; 后者只是前者的语法糖。x[(exp1, exp2, ..., expN)]
x[exp1, exp2, ..., expN]
基本切片将Python的基本概念扩展为N个维度。当obj是一个slice
对象(由start:stop:step
括号内的符号构成),一个整数或一个切片对象和整数的元组时,就会发生基本切片。Ellipsis
和newaxis
对象可以与这些也穿插。
从1.15.0版开始不推荐使用:为了保持与Numeric中的常用用法向后兼容,如果选择对象是任何list
包含slice
对象,Ellipsis
对象,对象,对象和对象的非ndarray和非元组序列(例如)
,则也会启动基本切片或newaxis
对象,但不适用于整数数组或其他嵌入式序列。
使用N个整数进行索引的最简单情况是返回表示对应项的数组标量。与Python中一样,所有索引均从零开始:对于第i个索引,有效范围为
where
是
数组形状的第i个元素。负索引被解释为从数组末尾开始计数(即,如果
,则表示
)。
通过基本切片生成的所有阵列始终都是 原始阵列的视图。
注意
NumPy切片会创建视图,而不是像内置Python序列(例如字符串,元组和列表)那样复制副本。从大型数组中提取一小部分时必须小心,因为提取后的小部分包含对大型原始数组的引用,直到从其派生的所有数组都被垃圾回收之前,该大型内存才会释放该内存。在这种情况下,copy()
建议使用显式的。
序列切片的标准规则适用于基于维(包括使用阶跃索引)的基本切片。需要记住的一些有用的概念包括:
基本切片语法是i:j:k
其中我是起始索引,
Ĵ是停止索引,并且ķ是步骤()。这将选择索引值为i,i + k,…,i +(m-1)k的m个元素(在相应维度中),其中
和q和r是通过将j-i除以k:j得到的商和余数-i = qk + r,因此
i +(m-1)k <j。
例
>>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> x[1:7:2]
array([1, 3, 5])
负数i和j解释为n + i和n + j,其中 n是相应维中元素的数量。负k使步进趋向较小的索引。
例
>>> x[-2:10]
array([8, 9])
>>> x[-3:3:-1]
array([7, 6, 5, 4])
假设n是要切片的维度中的元素数。然后,如果我没有给出其默认值为0 K> 0和
N - 1为ķ<0 。如果Ĵ没有给出其默认值为Ñ为K> 0
和-n-1为ķ<0 。如果未指定k,则默认为1。请注意,该
::
值与相同:
,表示选择沿该轴的所有索引。
例
>>> x[5:]
array([5, 6, 7, 8, 9])
如果选择元组中的对象数小于
N,则:
假定用于任何后续维。
例
>>> x = np.array([[[1],[2],[3]], [[4],[5],[6]]])
>>> x.shape
(2, 3, 1)
>>> x[1:2]
array([[[4],
[5],
[6]]])
Ellipsis
扩展到:
选择元组索引所有维度所需的对象数。在大多数情况下,这意味着扩展选择元组的长度为x.ndim
。可能只有一个省略号。
例
>>> x[...,0]
array([[1, 2, 3],
[4, 5, 6]])
newaxis
选择元组中的每个对象用于将结果选择的尺寸扩展一个单位长度尺寸。添加的维度是newaxis
对象在选择元组中的位置。
例
>>> x[:,np.newaxis,:,:].shape
(2, 1, 3, 1)
的整数,我,返回相同的值i:i+1
,除了返回的对象的维数由1。特别地降低,与所述选择元组p个元素的整数(以及所有其它条目:
)返回相应的子阵列与维N-1。如果N = 1,
则返回的对象是数组标量。这些对象在Scalars中进行了说明。
如果选择元组具有:
除第p个条目以外的所有条目(
它是一个切片对象)i:j:k
,则返回数组的维数N是通过串联由元素i,i + k,…,i +( m-1)k <j,
:
切片元组中具有多个非入口的基本切片的行为就像使用单个非:
入口重复应用切片,其中:
连续采用非入口(所有其他非:
入口均由代替:
)。因此,其
x[ind1,...,ind2,:]
行为类似于x[ind1][...,ind2,:]
基本切片。
警告
对于高级索引,以上内容不适用。
您可以使用切片来设置数组中的值,但是(与列表不同)您永远无法增长数组。要设置的值的大小
必须(可广播)为与相同的形状
。x[obj] = value
x[obj]
注意
请记住,切片元组始终可以构造为obj
并在x[obj]
表示法中使用。切片对象可以代替[start:stop:step]
符号在构造中使用。例如,x[1:10:5,::-1]
也可以实现为。这对于构造可用于任意维数组的通用代码很有用。obj = (slice(1,10,5), slice(None,None,-1)); x[obj]
当选择对象obj是非元组序列对象,ndarray
(数据类型为整数或布尔值的)非元组或具有至少一个序列对象或ndarray(数据类型为整数或布尔值)的元组时,将触发高级索引。有两种类型的高级索引:整数和布尔值。
高级索引总是返回数据的副本(与返回视图的基本切片相反)。
警告
高级索引的定义意味着与x[(1,2,3),]
根本不同x[(1,2,3)]
。后者等效于x[1,2,3]
将触发基本选择,而前者将触发高级索引。确保了解为什么会发生这种情况。
还应认识到,这x[[1,2,3]]
将触发高级索引编制,而由于上述不赞成使用的数字兼容性,
x[[1,2,slice(None)]]
将触发基本切片。
整数数组索引允许基于N维索引在数组中选择任意项目。每个整数数组代表该维度的多个索引。
当索引包含与要索引的数组一样多的整数数组时,索引是直接进行的,但与切片不同。
高级索引始终被广播并迭代为一个:
result[i_1, ..., i_M] == x[ind_1[i_1, ..., i_M], ind_2[i_1, ..., i_M],
..., ind_N[i_1, ..., i_M]]
请注意,结果形状与(广播)索引数组shape相同。ind_1, ..., ind_N
例
从每一行中,应选择一个特定元素。行索引是just
,列索引指定要为相应行选择的元素,此处。两者结合使用可以使用高级索引解决任务:[0, 1, 2]
[0, 1, 0]
>>> x = np.array([[1, 2], [3, 4], [5, 6]])
>>> x[[0, 1, 2], [0, 1, 0]]
array([1, 4, 5])
为了实现类似于上述基本切片的行为,可以使用广播。该功能ix_
可以帮助进行广播。最好用一个例子来理解。
例
从4x3数组中,应使用高级索引选择拐角元素。因此,需要选择列是其中之一而行是其中之一的所有元素。要使用高级索引,需要明确选择所有元素。使用前面解释的方法,可以编写:[0, 2]
[0, 3]
>>> x = array([[ 0, 1, 2],
... [ 3, 4, 5],
... [ 6, 7, 8],
... [ 9, 10, 11]])
>>> rows = np.array([[0, 0],
... [3, 3]], dtype=np.intp)
>>> columns = np.array([[0, 2],
... [0, 2]], dtype=np.intp)
>>> x[rows, columns]
array([[ 0, 2],
[ 9, 11]])
但是,由于上面的索引数组只会重复自身,因此可以使用广播(比较操作,例如
)来简化此操作:rows[:, np.newaxis] + columns
>>> rows = np.array([0, 3], dtype=np.intp)
>>> columns = np.array([0, 2], dtype=np.intp)
>>> rows[:, np.newaxis]
array([[0],
[3]])
>>> x[rows[:, np.newaxis], columns]
array([[ 0, 2],
[ 9, 11]])
该广播还可以使用以下功能实现ix_
:
>>> x[np.ix_(rows, columns)]
array([[ 0, 2],
[ 9, 11]])
请注意,np.ix_
如上例所示,在没有调用的情况下,只会选择对角线元素。对于使用多个高级索引建立索引,要记住的最重要的事情是。
当至少有一个切片(:
),省略号(...
)或newaxis
索引中(或数组的维数多于高级索引)时,行为可能会更加复杂。就像将每个高级索引元素的索引结果连接起来一样
在最简单的情况下,只有一个单一的指标先进。单个高级索引可以例如替换切片,并且结果数组将相同,但是,它是一个副本,并且可能具有不同的内存布局。如果可能的话,切片是优选的。
例
>>> x[1:2, 1:3]
array([[4, 5]])
>>> x[1:2, [1, 2]]
array([[4, 5]])
了解情况的最简单方法可能是根据结果形状进行思考。索引操作分为两部分,基本索引定义的子空间(不包括整数)和高级索引部分的子空间。需要区分索引组合的两种情况:
高级索引由切片Ellipsis
或分隔newaxis
。例如。x[arr1, :, arr2]
高级索引彼此相邻。例如,但不是,
因为这是这方面的高级索引。x[..., arr1, arr2, :]
x[arr1, :, 1]
1
在第一种情况下,由高级索引操作产生的维数首先出现在结果数组中,然后是子空间维数。在第二种情况下,将来自高级索引操作的维度与初始数组中的维度插入到结果数组中的相同位置(后一种逻辑使简单的高级索引行为像切片一样)。
例
假设x.shape
是(10,20,30)并且ind
是(2,3,4)形的索引intp
数组,则形状为(10,2,3,4,30),因为(20,)形子空间已被替换(2,3,4)形的广播索引子空间。如果我们让i,j,k在(2,3,4)形子空间上循环,则
。此示例产生与相同的结果。result = x[...,ind,:]
result[...,i,j,k,:] = x[...,ind[i,j,k],:]
x.take(ind, axis=-2)
例
让我们x.shape
为(10,20,30,40,50),并假设ind_1
以及ind_2
可播放的形状(2,3,4)。然后
x[:,ind_1,ind_2]
具有形状(10,2,3,4,40,50),因为来自X的(20,30)形子空间已被索引中的(2,3,4)子空间替代。但是,
x[:,ind_1,:,ind_2]
具有形状(2,3,4,10,30,50)是因为在索引子空间中没有明确的放置位置,因此它是从头开始的。始终可以使用
.transpose()
将子空间移动到所需的任何位置。请注意,此示例无法使用复制take
。
当obj是布尔类型的数组对象(例如,可以从比较运算符返回)时,就会发生这种高级索引。单个布尔索引数组实际上与x[obj.nonzero()]
如上所述的obj.nonzero()
返回obj.ndim
整数索引数组的元组(长度为)相同,该整数数组显示obj的True
元素。但是,当时速度更快。obj.shape == x.shape
如果为,则返回一维数组,其中填充了与obj
值相对应的x元素。搜索顺序将是C风格的行优先。如果obj在x的边界之外的条目中具有值,则将引发索引错误。如果obj小于x,则等同于用填充。obj.ndim == x.ndim
x[obj]
True
True
False
例
一个常见的用例是过滤所需的元素值。例如,可能希望从数组中选择不是NaN的所有条目:
>>> x = np.array([[1., 2.], [np.nan, 3.], [np.nan, np.nan]])
>>> x[~np.isnan(x)]
array([ 1., 2., 3.])
或希望为所有否定元素添加一个常量:
>>> x = np.array([1., -1., -2., 3])
>>> x[x < 0] += 20
>>> x
array([ 1., 19., 18., 3.])
通常,如果索引包含布尔数组,则结果将与插入obj.nonzero()
相同位置并使用上述整数数组索引机制相同。
等同于
。x[ind_1, boolean_array, ind_2]
x[(ind_1,) + boolean_array.nonzero() + (ind_2,)]
如果只有一个布尔数组,而没有整数索引数组,那么这很简单。必须注意只能采取以确保布尔指数具有完全相同的许多方面,它应该是与工作。
例
从数组中,选择所有总和小于或等于2的行:
>>> x = np.array([[0, 1], [1, 1], [2, 2]])
>>> rowsum = x.sum(-1)
>>> x[rowsum <= 2, :]
array([[0, 1],
[1, 1]])
但是,如果rowsum
还有两个维度:
>>> rowsum = x.sum(-1, keepdims=True)
>>> rowsum.shape
(3, 1)
>>> x[rowsum <= 2, :] # fails
IndexError: too many indices
>>> x[rowsum <= 2]
array([0, 1])
由于额外的维度,最后一个仅给出第一个元素。比较rowsum.nonzero()
以了解此示例。
通过obj.nonzero()
类比可以最好地理解将多个布尔索引数组或布尔与整数索引数组组合在一起的方法
。该函数ix_
还支持布尔数组,并且可以正常工作。
例
使用布尔索引来选择所有相加为偶数的行。同时,应使用高级整数索引选择第0列和第2列。使用此ix_
功能可以通过以下方式完成:
>>> x = array([[ 0, 1, 2],
... [ 3, 4, 5],
... [ 6, 7, 8],
... [ 9, 10, 11]])
>>> rows = (x.sum(-1) % 2) == 0
>>> rows
array([False, True, False, True])
>>> columns = [0, 2]
>>> x[np.ix_(rows, columns)]
array([[ 3, 5],
[ 9, 11]])
如果没有np.ix_
通话,将只选择对角线元素。
有无np.ix_
(比较整数数组示例):
>>> rows = rows.nonzero()[0]
>>> x[rows[:, np.newaxis], columns]
array([[ 3, 5],
[ 9, 11]])
这些是一些详细的注释,对于日常索引编制(不按特定顺序)不重要:
本地NumPy索引类型为intp
默认整数数组类型,并且可能与默认整数数组类型不同。intp
是足以安全地索引任何数组的最小数据类型;对于高级索引,它可能比其他类型更快。
对于高级分配,通常不保证迭代顺序。这意味着,如果一个元素被多次设置,则不可能预测最终结果。
空(元组)索引是零维数组中的完整标量索引。
如果尺寸为零,则x[()]
返回标量,否则x
为视图。另一方面,x[...]
总是返回一个视图。
如果索引中存在零维数组,并且它是全整数索引,则结果将是标量,而不是零维数组。(不会触发高级索引。)
当省略号(...
)存在但没有大小(即替换为零
:
)时,结果仍将始终是数组。如果没有高级索引,则为视图,否则为副本。
nonzero
布尔数组的等价不适用于零维布尔数组。
如果高级索引操作的结果没有元素,但单个索引超出范围,IndexError
则不确定是否引发an (例如,超出范围)。x[[], [123]]
123
如果在分配过程中发生转换错误(例如,使用字符串序列更新数字数组),则分配给该数组的结果可能会以不可预测的部分更新状态结束。但是,如果发生任何其他错误(例如越界索引),则数组将保持不变。
对于每个索引操作,都会优化高级索引结果的存储器布局,并且无法假定特定的存储器顺序。
当使用一个子类(尤其是其操纵它的形状),默认ndarray.__setitem__
行为会调用__getitem__
的
基本索引而不是先进的索引。对于此类子类,可能最好在数据上ndarray.__setitem__
使用基类 ndarray视图进行调用。这必须如果子类来完成__getitem__
不返回意见。
也可以看看
如果ndarray
对象是结构化数组
,则可以通过使用类似于字典的字符串对数组进行索引来访问数组的字段。
索引x['field-name']
将返回一个新的视图到数组,该视图的形状与x相同(当字段是子数组时除外),但具有数据类型,x.dtype['field-name']
并且仅包含指定字段中的部分数据。还
记录阵列标量可以被“索引”这种方式。
也可以使用字段名称列表(例如) 对结构化数组进行索引
x[['field-name1','field-name2']]
。从NumPy 1.16开始,它将返回仅包含这些字段的视图。在旧版本的numpy中,它返回了一个副本。有关多字段索引的更多信息,请参见结构化数组的用户指南部分。
如果访问的字段是子数组,则子数组的尺寸将附加到结果的形状上。
例
>>> x = np.zeros((2,2), dtype=[('a', np.int32), ('b', np.float64, (3,3))])
>>> x['a'].shape
(2, 2)
>>> x['a'].dtype
dtype('int32')
>>> x['b'].shape
(2, 2, 3, 3)
>>> x['b'].dtype
dtype('float64')