numpy学习——数组的分片和索引以及高级索引(整数索引,布尔索引)

基本的分片和索引操作

  • 多维数组的分片操作:

    >>> a = np.arange(27).reshape(3,3,3)
    
    >>> a
    
    array([[[ 0,  1,  2],
            [ 3,  4,  5],
            [ 6,  7,  8]],
    
           [[ 9, 10, 11],
            [12, 13, 14],
            [15, 16, 17]],
    
           [[18, 19, 20],
            [21, 22, 23],
            [24, 25, 26]]])
    

    对三维数组,就要在三个维度上去运用切片

    >>> a[:,0,1]
    
    array([ 1, 10, 19])
    

    : 代表第一个维度,全部都遍历。0表示第二个维度取第一个,即:[0,1,2],[9,10,11],[18,19,20],1表示第三个维度的第二个数字,就可以得到[1,10,19]

    如果想取到1,4,7怎么办?

    首先第一个维度先取第一个,即0,第二个维度是全部取的,因为每个都要。第三个维度取第二个数,即1。故:

    >>> a[0,:,1]
    
    array([1, 4, 7])
    

    除此之外,依旧可以取负值切片,如取7,4,1

    >>> a[0,::-1,1]
    
    array([7, 4, 1])
    

高级索引

当方括号内的索引方式不再是之前介绍的简单序列的时候,就会触发高级索引。高级索引包括整数索引和布尔索引。

  • 整数索引

    对于一维数组而言,使用数组进行索引,返回的结果和索引数组的形状一样,不同的地方在于被索引数组的相关值会替代索引数组对应位置的值。

    >>> test = np.arange(10)
    
    >>> test[np.array([[1,2],[3,4]])]
    
    array([[1, 2],
           [3, 4]])
    

    由于1,2,3,4位置上的数字恰好是1,2,3,4。所以返回如上结果。

    再看另一组例子,依旧用之前生成好的a:

    >>> a
    
    array([[[ 0,  1,  2],
            [ 3,  4,  5],
            [ 6,  7,  8]],
    
           [[ 9, 10, 11],
            [12, 13, 14],
            [15, 16, 17]],
    
           [[18, 19, 20],
            [21, 22, 23],
            [24, 25, 26]]])
    

    如何取出0,13,26呢?

    首先分析,这里是三维数组。在每一个维度上去取,第一维度上每一个都应该取到。即[0,1,2]都需要取到。

    第二维度上,取到的分别是第一个[0,1,2],第二个[12,13,14],第三个[24,25,26]。然后我们分别取得是第一个:0,第二个:13,第三个:26。故

    >>> a[[0,1,2],[0,1,2],[0,1,2]]
    
    array([ 0, 13, 26])
    

    如果是6,10,20呢?同样分析后应该是

    >>> a[[0,1,2],[2,0,0],[0,1,2]]
    
    array([ 6, 10, 20])
    

    要和之前讲的索引数组进行区分

    >>> a[np.array([[0,1,2],[2,0,0],[0,1,2]])]
    
    array([[[[ 0,  1,  2],
             [ 3,  4,  5],
             [ 6,  7,  8]],
    
            [[ 9, 10, 11],
             [12, 13, 14],
             [15, 16, 17]],
    
            [[18, 19, 20],
             [21, 22, 23],
             [24, 25, 26]]],
    
    
           [[[18, 19, 20],
             [21, 22, 23],
             [24, 25, 26]],
    
            [[ 0,  1,  2],
             [ 3,  4,  5],
             [ 6,  7,  8]],
    
            [[ 0,  1,  2],
             [ 3,  4,  5],
             [ 6,  7,  8]]],
    
    
           [[[ 0,  1,  2],
             [ 3,  4,  5],
             [ 6,  7,  8]],
    
            [[ 9, 10, 11],
             [12, 13, 14],
             [15, 16, 17]],
    
            [[18, 19, 20],
             [21, 22, 23],
             [24, 25, 26]]]])
    

    我们有提到:返回的结果和索引数组的形状一样。这里的[0,1,2]代表的就是三维数组的第一维的第一个位置,是用我们a里的第三维的三块填充的(按照[0,1,2]三个部分的顺序)。

    再看下一个例子:

>>> a

array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8]],

       [[ 9, 10, 11],
        [12, 13, 14],
        [15, 16, 17]],

       [[18, 19, 20],
        [21, 22, 23],
        [24, 25, 26]]])

>>> a[:,[2,0,0],[0,1,0]]

array([[ 6,  1,  0],
       [15, 10,  9],
       [24, 19, 18]])

这里可以看到我们的切片:和[0,1,2]是不一样的。(为啥?)

使用:时,先取第一维的第一个部分,再第二维的第三个部分[6,7,8],之后取第三维的第一个:6。之后,取二维的第一个部分[0,1,2]再取第三维的第二个:0。……

而使用[0,1,2]时,取过[6,7,8]中的6之后,直接跳到第一维的第二个部分 [[ 9, 10, 11],[12, 13, 14],[15, 16, 17]],不会继续在第一维第一部分循环。

  • 布尔索引

    当索引的方式是布尔数组的时候,会触发布尔索引。

    首先我们可以使用random下面的and()函数生成一个10*4的均匀分布的二维数组,之后定义一个长度为10的一维数组,数组元素是一些人名,每行数据和人名一一对应

    >>> data = np.random.rand(40).reshape(10,4)
    
    >>> data
    
    array([[0.75224117, 0.07255487, 0.15486979, 0.99832024],
           [0.89716759, 0.45973014, 0.69035348, 0.41042202],
           [0.8642536 , 0.24061544, 0.28480594, 0.66261885],
           [0.63386443, 0.00841045, 0.99501351, 0.49271741]])
    
    >>> name = np.array(['小明', '小张', '小王', '小李', '小宋', '李华', '小王', '小张', '小王', '小王'])
    
    array(['小明', '小张', '小王', '小李', '小宋', '李华', '小王', '小张', '小王', '小王'],
          dtype='<U2')
    
    >>> data[name=='小王']
    
    array([[0.75224117, 0.07255487, 0.15486979, 0.99832024],
           [0.89716759, 0.45973014, 0.69035348, 0.41042202],
           [0.8642536 , 0.24061544, 0.28480594, 0.66261885],
           [0.63386443, 0.00841045, 0.99501351, 0.49271741]])
    

    布尔索引的同时也可以进行分片操作

    >>> data[name=='小王', 1:]
    
    array([[0.07255487, 0.15486979, 0.99832024],
           [0.45973014, 0.69035348, 0.41042202],
           [0.24061544, 0.28480594, 0.66261885],
           [0.00841045, 0.99501351, 0.49271741]])
    

    也可以使用不等号!=去排除数据

    >>> data[name!='小王']
    
    array([[0.6472885 , 0.3815376 , 0.55129018, 0.27300518],
           [0.06804647, 0.38165689, 0.70944563, 0.95890571],
           [0.54024513, 0.86783983, 0.03735209, 0.80200385],
           [0.46726378, 0.73882054, 0.20409086, 0.94286587],
           [0.27076598, 0.58085051, 0.0307553 , 0.76344933],
           [0.20232403, 0.73624633, 0.26808471, 0.74315558]])
    

    可以使用& | ~ (即:与、或、非)进行运算。

    * 布尔索引的简单应用

    可以用布尔索引去筛选出值为NAN的元素并剔除。

    >>> x = np.array([[1,2],[np.nan,3],[np.nan,np.nan]])
    
    >>> x
    
    array([[ 1.,  2.],
           [nan,  3.],
           [nan, nan]])
    
    >>> x[~np.isnan(x)]
    
    array([1., 2., 3.])
    

    也可以对某些值进行修改。比如给数组内元素小于1的元素加上一个值。

    >>> x = np.array([1,-1,-2,3])
    
    >>> x[x<0] += 20
    
    >>> x
    
    array([ 1, 19, 18,  3])
    

    可以使用nonzero()来生成元素值非0的整数数组索引

    >>> x = np.array([[1,2],[np.nan,3],[np.nan,np.nan]])
    
    >>> x
    
    array([[ 1.,  2.],
           [nan,  3.],
           [nan, nan]])
    
    >>> x.nonzero()
    
    (array([0, 0, 1, 1, 2, 2], dtype=int64),
     array([0, 1, 0, 1, 0, 1], dtype=int64))
    

    nan不是0,因此我们不是0的坐标为(0,0),(0,1),……,(2,0),(2,1)

    布尔索引的数值必须和被索引数值对应轴的长度一样,否则会引发异常。

猜你喜欢

转载自blog.csdn.net/m0_50470999/article/details/108450726