索引

ndarrays 可以使用标准的python编制索引 x[obj] 语法,在哪里 x 是数组和 obj 选择。有三种可用的索引:字段访问、基本切片、高级索引。哪一个发生取决于 obj .

注解

在 Python 中, x[(exp1, exp2, ..., expN)] 等于 x[exp1, exp2, ..., expN] 后者只是前者的句法糖分。

基本切片和索引

基本切片将python的切片基本概念扩展到n维。基本切片发生在 obj 是一个 slice 对象(由构造 start:stop:step 括号内的符号)、整数或切片对象和整数的元组。 Ellipsisnewaxis 对象也可以散布在其中。

1.15.0 版后已移除: 为了保持向后兼容数字中的常见用法,如果选择对象是任何非ndarray和非元组序列(例如 listslice 对象 Ellipsis 对象,或 newaxis 对象,但不适用于整数数组或其他嵌入序列。

索引的最简单情况 N 整数返回 array scalar 表示对应的项。与Python一样,所有索引都是从零开始的:对于 i 第四指标 n_i ,有效范围为 0 \le n_i < d_i 在哪里? d_ii -数组形状的第个元素。负索引被解释为从数组末尾开始计数。( i.e. 如果 n_i < 0 这意味着 n_i + d_i

所有由基本切片生成的数组 views 原始数组的。

注解

NumPy 的切片创建了 view 而不是像内置的python序列(如string、tuple和list)那样的副本。在从大型数组中提取一小部分时必须小心,因为提取的小部分包含对大型原始数组的引用,在对其派生的所有数组进行垃圾收集之前,不会释放这些数组的内存。在这种情况下, copy() 建议使用。

序列切片的标准规则适用于基于每个维度的基本切片(包括使用步骤索引)。需要记住的一些有用概念包括:

  • 基本切片语法是 i:j:k 在哪里? i 是起始索引, j 是停止索引,并且 k 就是台阶 (k\neq0 )这将选择 m 具有索引值的元素(在相应维度中) iI+Ki + (m - 1) k 在哪里? m = q + (r\neq0)qr 商和余数是通过除法得到的吗? j - i 通过 kj - i = q k + 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])
    
  • 否定的 ij 被解释为 n+in+j 在哪里? n 是对应维度中的元素数。否定的 k 使逐步向较小的指数迈进。

    例子

    >>> x[-2:10]
    array([8, 9])
    >>> x[-3:3:-1]
    array([7, 6, 5, 4])
    
  • 假定 n 是要切片的维度中的元素数。然后,如果 i 没有将其默认为0 k > 0n - 1 对于 k < 0 .如果 j 没有默认为 n 对于 k > 0-n-1 对于 k < 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:i+1 除了 返回对象的维数减少1。特别是,一个带有 p -元素一个整数(以及所有其他条目 : )返回具有维度的相应子数组 N - 1 .如果 N = 1 然后返回的对象是数组标量。这些对象在 标量 .

  • 如果选择元组包含所有条目 : 除了 p -是一个切片对象的条目 i:j:k ,则返回的数组具有维度 N 通过连接元素的整数索引返回的子数组形成 ii+ki + (m - 1) k < j

  • 基本切片在切片元组中有多个非``:条目,其作用类似于使用单个非`:``条目重复切片的应用,其中非`:`:``条目依次被替换为 ``: )因此, x[ind1,...,ind2,:] 行为像 x[ind1][...,ind2,:] 在基本切片下。

    警告

    以上是 not 对于高级索引,为true。

  • 您可以使用切片来设置数组中的值,但是(与列表不同)您永远不能扩大数组。要设置的值的大小 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] . 这对于构造在任意维数组上工作的通用代码很有用。

numpy.newaxis

这个 newaxis 对象可用于所有切片操作,以创建长度为1的轴。 newaxis 是“none”的别名,可以使用“none”代替具有相同结果的别名。

高级索引

当选择对象, obj ,是非元组序列对象, ndarray (指数据类型integer或bool),或具有至少一个序列对象或ndarray(指数据类型integer或bool)的元组。高级索引有两种类型:整数和布尔值。

高级索引始终返回 copy 数据(与返回 view

警告

高级索引的定义意味着 x[(1,2,3),] 根本不同于 x[(1,2,3)] . 后者相当于 x[1,2,3] 它将触发基本选择,而前者将触发高级索引。一定要理解为什么会发生这种情况。

也要认识到 x[[1,2,3]] 将触发高级索引,但是由于上述不推荐使用的数字兼容性, x[[1,2,slice(None)]] 将触发基本切片。

整数数组索引

整数数组索引允许根据数组中的任意项 N -尺寸索引。每个整数数组表示该维度中的索引数。

纯整数数组索引

当索引包含的整数数组与被索引的数组具有维数相同时,索引是直接向前的,但与切片不同。

高级索引总是 broadcast 并迭代为 one ::

result[i_1, ..., i_M] == x[ind_1[i_1, ..., i_M], ind_2[i_1, ..., i_M],
                           ..., ind_N[i_1, ..., i_M]]

请注意,结果形状与(广播)索引数组形状相同 ind_1, ..., ind_N .

例子

从每一行中,应该选择一个特定的元素。行索引只是 [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 = np.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]])

理解这种情况的最简单方法可能是根据结果形状进行思考。索引操作分为两部分:基本索引定义的子空间(不包括整数)和高级索引部分的子空间。需要区分两种索引组合情况:

  • 高级索引由一个切片分隔, Ellipsisnewaxis . 例如 x[arr1, :, arr2] .

  • 高级索引彼此相邻。例如 x[..., arr1, arr2, :] 但是 not x[arr1, :, 1] 自从 1 是这方面的高级索引。

在第一种情况下,高级索引操作产生的维度首先出现在结果数组中,其次是子空间维度。在第二种情况下,高级索引操作中的维度插入到结果数组中的位置与它们在初始数组中的位置相同(后一种逻辑使简单高级索引的行为类似于切片)。

例子

假设 x.shape IS(10、20、30)和 ind 是(2,3,4)形索引 intp 数组,然后 result = x[...,ind,:] 具有形状(10,2,3,4,30),因为(20,)形子空间已被(2,3,4)形广播索引子空间替换。如果我们让 我,J,K 然后循环(2,3,4)形子空间 result[...,i,j,k,:] = x[...,ind[i,j,k],:] . 此示例生成的结果与 x.take(ind, axis=-2) .

例子

x.shape Be(10,20,30,40,50)并假设 ind_1ind_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 )整数索引数组的 True 要素 obj . 但是,当 obj.shape == x.shape .

如果 obj.ndim == x.ndimx[obj] 返回用以下元素填充的一维数组 x 对应于 True 价值观 obj . 搜索顺序是 row-major C风格。如果 objTrue 值位于超出 x ,则将引发索引错误。如果 obj 小于 x 它和填充它是一样的 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,)] .

如果只有一个布尔数组且不存在整数索引数组,则这是直接前进的。必须注意确保布尔索引 确切地 尽可能多的尺寸。

例子

从数组中,选择总计小于或等于两行的所有行:

>>> x = np.array([[0, 1], [1, 1], [2, 2]])
>>> rowsum = x.sum(-1)
>>> x[rowsum <= 2, :]
array([[0, 1],
       [1, 1]])

将多个布尔索引数组或布尔值与整数索引数组组合可以用 obj.nonzero() 类比。函数 ix_ 也支持布尔数组,并且工作时不会有任何意外。

例子

使用布尔索引选择所有添加到偶数的行。同时,应使用高级整数索引选择列0和2。使用 ix_ 功能可通过以下方式完成:

>>> x = np.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[()] 返回A 标量 如果 x 是零维的,否则是视图。另一方面 x[...] 始终返回视图。

  • 如果索引中存在零维数组 and 它是一个完整的整数索引,结果将是 标量 不是零维数组。(不会触发高级索引。)

  • 当一个省略号 (... )存在但没有大小(即替换零 : )结果仍然是一个数组。如果不存在高级索引,则为视图,否则为副本。

  • 这个 nonzero 对于零维布尔数组,布尔数组的等效性不成立。

  • 当高级索引操作的结果没有元素但单个索引超出界限时,无论是否 IndexError 提升未定义(例如 x[[], [123]] 具有 123 越界)。

  • 当A 铸造 分配过程中发生错误(例如,使用字符串序列更新数值数组),分配给的数组可能最终处于不可预测的部分更新状态。但是,如果发生任何其他错误(如越界索引),数组将保持不变。

  • 高级索引结果的内存布局针对每个索引操作进行了优化,不能假定特定的内存顺序。

  • 当使用子类(尤其是操纵其形状的子类)时,默认 ndarray.__setitem__ 行为需要 __getitem__ 对于 基本的 索引,但不用于 先进的 索引。对于这样的子类,最好调用 ndarray.__setitem__ 用一个 基类 数据的ndarray视图。这个 must 如果子类 __getitem__ 不返回视图。

现场访问

如果 ndarray 对象是结构化数组 fields 可以通过使用类似字典的字符串对数组进行索引来访问数组的。

索引 x['field-name'] 返回新的 view 数组,其形状与 x (字段是子数组时除外)但属于数据类型 x.dtype['field-name'] 并且只包含指定字段中的部分数据。阿尔索 record array 标量可以这样“索引”。

索引到结构化数组也可以通过字段名列表来完成, e.g. 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')

平面迭代器索引

x.flat 返回将在整个数组上迭代的迭代器(采用C-连续样式,最后一个索引的变化速度最快)。只要选择对象不是元组,就可以使用基本切片或高级索引对迭代器对象进行索引。这应该从以下事实中清楚地说明: x.flat 是一维视图。它可以用于带一维C样式平面索引的整数索引。因此,任何返回数组的形状都是整数索引对象的形状。