Python numpy之高级索引

1,416 阅读5分钟

image.png

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

前言

继上一期 numpy 基本索引与切片中,numpy 借鉴了标准的Python x[obj] 语法进行索引。

根据 obj 对象类型不同,索引主要分为 基本索引和高级索引。

image.png

在单元素索引中,对于一维数组来说索引返回的是原始数组的副本。对于N维数组,当少于数组维数的索引对象,则返回是原始数组的视图。

基本索引中,我们可以使用 start:stop:step 来进行切片操作,基本操作逻辑与Python list、字符串等支出正索引和负索引,当::时,是取所有数组元素值。

同时在进行切片过程中,要确保设置的值的大小与原数组形状保持一致。

但是,start:stop:step 这种切片方式不适合高级索引。

相信大家,一定充满对高级索引的好奇,哪接下来我们开始学习高级索引相关概念,Let's go~~

1. 高级索引

  • 什么是高级索引?

    numpy 模块索引是沿用 Python 标准的索引方式 x[obj]。

    • 触发高级索引条件

      • 当 obj 是非元组序列
      • ndarray的数据元素类型为布尔类型
      • 数据类型为整数或布尔值的元组

    高级索引总是返回的数据的副本,与基本切片返回视图相反。

2. 整数数组索引

2.1 什么是整数数组索引?

整数数组索引是以元素是整数类型的ndarray对象进行索引查询多个任意数据元素。

与基本索引和切片一样,索引数组支持正索引和负索引。

  • 整数数组索引为ndarray对象

    (an ndarray(of data type integer or bool))

    >>> import numpy as np
    >>> intarr = np.arange(12)
    >>> intarr
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
    >>> intarr[np.array([3,5,7,9])]
    array([3, 5, 7, 9])
    >>>
    

    如果索引中,对象不是ndarray,则系统会报TypeError错误

    >>> intarr([3,5,7,9])
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'numpy.ndarray' object is not callable
    
  • 整数数组索引为list对象

    a non-tuple sequence object

    >>> intarr[[3,5,7,9]]
    array([3, 5, 7, 9])
    
  • 整数数组索引为包含序列的tuple对象

    >>> intarr[([3,5,7,9])]
    array([3, 5, 7, 9])
    
    

索引值为负数时,其工作原理与切片一样,从数组未位开始进行查找

>>> intarr
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
>>> intarr[([1,2,-3,-1])]
array([ 1,  2,  9, 11])
>>>

当索引值超时范围是,系统会报IndexError

 >>> intarr[([13])]
 Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
 IndexError: index 13 is out of bounds for axis 0 with size 12
 >>>

2.2 多维数组的整数数组索引

  • 当多维数组与索引维度一样多时,numpy 内部会进行广播和迭代,如下栗子。

    >>> intarr2 = np.array([[2,3],[4,5],[8,9]])
    >>> intarr2
    array([[2, 3],
           [4, 5],
           [8, 9]])
    >>> intarr2[[1,-1]]
    array([[4, 5],
           [8, 9]])
    

同理,当索引数组值大于原数组时,会触发 numpy indexError

>>> intarr2[[3,1]]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: index 3 is out of bounds for axis 0 with size 3
>>>

2.3 多维数组的整数数组应用

  • 多维数组整数索引常规操作

    官方给出高级索引的迭代公式

    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一样。 比如,我们下面的案例,intarr3[np.array([1,2,3]),np.array([1,3,2])] = intarr3[1,1] intarr3[2,3] intarr3[3,2]

    >>> intarr3 = np.arange(20).reshape(5,4)
    >>> intarr3
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 4,1 15],
           [16, 17, 18, 19]])
    >>> intarr3[np.array([1,2,3]),np.array([1,3,2])]
    array([ 5, 11, 14])
    >>>
    

我们之前在了解到 numpy 广播规则时,触发广播后,输出的结果shape与原数组shape保持一致,否则的话,系统会报shape不一致的异常

  >>> intarr3[np.array([1,2,3]),np.array([1,3])]
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (3,) (2,)
  >>>

  • numpy 广播机制允许与其他索引重叠

    如下案例,我们可以看到intarr3[np.array([1,2,3]),1]= intarr3[1,1]intarr3[2,1]intarr3[3,1]

    >>> intarr3
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15],
           [16, 17, 18, 19]])
    >>> intarr3[np.array([1,2,3]),1]
    array([ 5,  9, 13])
    >>>
    

3. 布尔索引

Numpy 模块中,当索引对象为布尔类型时,也会触发高级索引。

布尔索引是布尔运算来获取指定的元素数据

布尔索引最常见的应用是过滤所需要的的元素值

  >>> intarr3
array([[ 0,  1,  2,  3],
     [ 4,  5,  6,  7],
     [ 8,  9, 10, 11],
     [12, 13, 14, 15],
     [16, 17, 18, 19]])
>>> intarr3[[intarr3>5]]
array([ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>>

4. 花式索引

花式索引是整数数组索引的拓展,专门针对多个索引数组时,调用np.ix_来实现广播。

>>> intarr3
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19]])
>>> intarr3[[intarr3>5]]
array([ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> intarr3[[3,4,4,1]]
array([[12, 13, 14, 15],
       [16, 17, 18, 19],
       [16, 17, 18, 19],
       [ 4,  5,  6,  7]])
>>> intarr3[[-3,-1,-1,-1]]
array([[ 8,  9, 10, 11],
       [16, 17, 18, 19],
       [16, 17, 18, 19],
       [16, 17, 18, 19]])

类似切片的功能,高级索引可以调用np.ix_方法实现广播机制

>>> intarr3[np.ix_([-3,-1,-1,-1],[0,1,2,3])]
array([[ 8,  9, 10, 11],
       [16, 17, 18, 19],
       [16, 17, 18, 19],
       [16, 17, 18, 19]])
>>>

总结

本期,对numpy 模块中关于高级索引两种类型整数数组索引和布尔索引相关操作,进行学习。

相对于基本索引来说,高级索引可以帮助我们实现更多的功能,如迭代和广播

以上是本期内容,欢迎大佬们点赞评论,下期见~