添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

对于内容的引用说明:

Numpy 笔记(二): 多维数组的切片(slicing)和索引(indexing): http://www.zmonster.me/2016/03/09/numpy-slicing-and-indexing.html, 感谢 ZMonster's Blog 原创内容。

ndarray对象的内容可以通过索引或切片来访问和修改,ndarray对象中的元素遵循基于零的索引。 有三种可用的索引方法: 字段访问,基本切片 高级索引

基本切片是 Python 中基本切片概念到 n 维的扩展。 通过将 start stop step 参数提供给内置的 slice 函数来构造一个 Python slice 对象。 此 slice 对象被传递给数组来提取数组的一部分。简而言之,切片是有索性。

1、基本原理是这样:

1、切片需要使用序列生成,即冒号运算符‘:‘,一个单冒号为选取整个序列,也可以指定范围,如1:5表示1~4(包括)这4个元素。同时可以指定步长如1:6:2表示选取1,3,5这3个元素,其中start=1,stop=6,step=2,这个与Python的列表切片是一致的。

2、然后,使用逗号,来区分轴(axis),轴可以简单地理解为在某个维度上的投影。例如axis=0指的就是行,axis=1指的就是列。那么第一个选取就是行,第二个选取的就是列,中间用逗号隔开,例如下面的一条语句。

arr[:,2]
  • a[n,m,k,...] :每个维度一个索引值,最外list中第n个元素,倒数第二外list中第m个元素,以此类推。如果n为负数,则返回倒着数第n个元素。
  • a[n1:m1:k1,n2:m2:k2,n3:m3:k3,...] :每个维度的切片方法与一维数组相同。顺序为从外到内
  • 3、切片操作

    Numpy中多维数组的切片操作与Python中list的切片操作一样,同样由start,stop,step三个部分组成。

    import numpy as np
    a = np.arange(10)
    s = slice(2,7,2)
    print(a[s])
    

    输出如下:

    [2  4  6]
    

    在上面的例子中, ndarray 对象由 arange() 函数创建。 然后,分别用起始,终止和步长值 2 7 2 定义切片对象。 当这个切片对象传递给 ndarray 时,会对它的一部分进行切片,从索引 2 7 ,步长为 2

    通过将由冒号分隔的切片参数( start:stop:step )直接提供给 ndarray 对象,也可以获得相同的结果。

    import numpy as np
    a = np.arange(10)
    b = a[2:7:2]
    print(b)
    

    输出如下:

    [2  4  6]
    

    如果只输入一个参数,则将返回与索引对应的单个项目。 如果使用 a: ,则从该索引向后的所有项目将被提取。 如果使用两个参数(以 : 分隔),则对两个索引(不包括停止索引)之间的元素以默认步骤进行切片。

    #对单个元素进行切片  
    import numpy as np
    a = np.arange(10)
    b = a[5]
    print(b)
    

    输出如下:

    #对始于索引的元素进行切片  
    import numpy as np
    a = np.arange(10)
    print(a[2:])
    

    输出如下:

    [2  3  4  5  6  7  8  9]
    
    #对索引之间的元素进行切片  
    import numpy as np
    a = np.arange(10)
    print(a[2:5])
    

    输出如下:

    [2  3  4]
    

    上面的描述也可用于多维ndarray

    import numpy as np
    a = np.array([[1,2,3],[3,4,5],[4,5,6]])
    print(a)
    # 对始于索引的元素进行切片
    print('\n现在我们从索引 a[1:] 开始对数组切片')
    print(a[1:])
    

    输出如下:

    [[1 2 3]
     [3 4 5]
     [4 5 6]]
    现在我们从索引 a[1:] 开始对数组切片
    [[3 4 5]
     [4 5 6]]
    

    切片还可以包括省略号(...),来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的ndarray

    #省略号必须是三个
    #最开始的数组
    import numpy as np
    a = np.array([[1,2,3],[3,4,5],[4,5,6]])
    print(a)
    # 这会返回第二列元素的数组:
    print('\n第二列的元素是:')
    print(a[...,1]) 
    # 现在我们从第二行切片所有元素:
    print('\n第二行的元素是:')
    print(a[1,...])
    # 现在我们从第二列向后切片所有元素:
    print('\n第二列及其剩余元素是:')
    print(a[...,1:])
    

    输出如下:

    我们的数组是:
    [[1 2 3]
     [3 4 5]
     [4 5 6]]
    第二列的元素是:
    [2 4 5]
    第二行的元素是:
    [3 4 5]
    第二列及其剩余元素是:
    [[2 3]
     [4 5]
     [5 6]]
    

    4、索性操作

    最简单的情况,对于一个多维数组来说,最简单的情况就是访问其中一个特定位置的元素了,如下所示:

    # coding: utf-8
    import numpy as np
    arr = np.array([
        [1, 2, 3, 4],
        [2, 4, 6, 8],
        [3, 6, 9, 12],
        [4, 8, 12, 16]
    print( '第二行第二列的值:', arr[1, 1])
    
    第二行第二列的值: 4
    

    相比之下,如果用Python的list来表示上述二维数组,获取同一个位置的元素的方法为:

    # coding: utf-8
    arr = [
        [1, 2, 3, 4],
        [2, 4, 6, 8],
        [3, 6, 9, 12],
        [4, 8, 12, 16]
    print ('第二行第二列的值:', arr[1][1])
        print ('第二行第二列的值(尝试用 Numpy 的方式获取):', arr[1, 1])
    except Exception as e:
        print(str(e))
    

    输出如下:

    第二行第二列的值: 4
    list indices must be integers or slices, not tuple
    

    如果只是二维数组,这种差别可能看起来并不大,但想象一下假如有一个10维的数组,用Python的标准做法需要写10对中括号,而用Numpy依然只需要一对。

    获取多个元素

    事实上,在Numpy的索引操作方式`x=arr[obj]`中,obj不仅仅可以是一个用逗号分隔开的数字序列,还可以是更复杂的内容。

  • 用逗号分隔的数组序列

  • 序列的长度和多维数组的维数要一致
  • 序列中每个数组的长度要一致
  • import numpy as np
    arr = np.array([
        [1, 2, 3, 4],
        [2, 4, 6, 8],
        [3, 6, 9, 12],
        [4, 8, 12, 16]
    print(arr[[0, 2], [3, 1]])
    
    [4 6]
    

    以上面这个例子来说,其含义是:选择第一行和第三行,然后对第一行选择第四列,对第三行选择第二列。

    2.boolean/maskindex

    这个不太好翻译,所以就用原来的英语表达。

    所谓booleanindex,就是用一个由boolean类型值组成的数组来选择元素的方法。比如说对下面这样多维数组

    array([[1, 2, 3, 4],
           [2, 4, 6, 8],
           [3, 6, 9, 12],
           [4, 8, 12, 16]])
    

    如果要取其中值大于5的元素,就可以用上 boolean index 了,如下所示:

    import numpy as np
    arr = np.array([[1, 2, 3, 4],
                    [2, 4, 6, 8],
                    [3, 6, 9, 12],
                    [4, 8, 12, 16]])
    mask = arr 
    print ('boolean mask is:')
    print (mask)
    print (arr[mask])
    

    输出如下:

    boolean mask is:
    [[False False False False]
     [False False  True  True]
     [False  True  True  True]
     [False  True  True  True]]
    [ 6  8  6  9 12  8 12 16]
    

    除了比较运算能产生booleanmask数组以外,Numpy本身也提供了一些工具方法:

  • numpy.iscomplex
  • numpy.isreal
  • numpy.isfinite
  • numpy.isinf
  • numpy.isnan
  • 5、切片和索引的同异

    切片和索引都是访问多维数组中元素的方法,这是两者的共同点,不同之处有:

  • 切片得到的是原多维数组的一个视图(view),修改切片中的内容会导致原多维数组的内容也发生变化
  • 切片得到在多维数组中连续(或按特定步长连续)排列的值,而索引可以得到任意位置的值,自由度更大一些
  • 不考虑第一点的话,切片的操作是可以用索引操作来实现的,不过这没有必要就是了。

    对于第一点,见下面的实验:

    import numpy as np
    arr = np.arange(12).reshape(2, 6)
    print('array is:')
    print( arr)
    slc = arr[:, 2:5]
    print ('slice is:')
    print (slc)
    slc[1, 2] = 10000
    print ('modified slice is:')
    print (slc)
    print ('array is now:')
    print (arr)
    

    输出如下:

    array is:
    [[ 0  1  2  3  4  5]
     [ 6  7  8  9 10 11]]
    slice is:
    [[ 2  3  4]
     [ 8  9 10]]
    modified slice is:
    [[    2     3     4]
     [    8     9 10000]]
    array is now:
    [[    0     1     2     3     4     5]
     [    6     7     8     9 10000    11]]