Python科学计算(第2版)
上QQ阅读APP看书,第一时间看更新

2.1.4 存取元素

可以使用和列表相同的方式对数组的元素进行存取:

    a = np.arange(10)
    a
    array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

●a[5]:用整数作为下标可以获取数组中的某个元素。

●a[3:5]:用切片作为下标获取数组的一部分,包括a[3]但不包括a[5]。

●a[:5]:切片中省略开始下标,表示从a[0]开始。

●a[:-1]:下标可以使用负数,表示从数组最后往前数。

●a[1:-1:2]:切片中的第三个参数表示步长,2表示隔一个元素取一个元素。

●a[::-1]:省略切片的开始下标和结束下标,步长为-1,整个数组头尾颠倒。

●a[5:1:-2]:步长为负数时,开始下标必须大于结束下标。

下标还可以用来修改元素的值:

    a[2:4] = 100, 101
    a
    array([  0,   1, 100, 101,   4,   5,   6,   7,   8,   9])

和列表不同的是,通过切片获取的新的数组是原始数组的一个视图。它与原始数组共享同一块数据存储空间。下面的程序将b的第2个元素修改为-10,a的第5个元素也同时被修改为-10,因为它们在内存中的地址相同。

    b = a[3:7] # 通过切片产生一个新的数组b,b和a共享同一块数据存储空间
    b[2] = -10 # 将b的第2个元素修改为-10
             b                                    a                         
    --------------------  --------------------------------------------------
    [101,   4, -10,   6]  [  0,   1, 100, 101,   4, -10,   6,   7,   8,   9]

除了使用切片下标存取元素之外,NumPy还提供了整数列表、整数数组和布尔数组等几种高级下标存取方法。

当使用整数列表对数组元素进行存取时,将使用列表中的每个元素作为下标。使用列表作为下标得到的数组不和原始数组共享数据:

    x = np.arange(10, 1, -1)
    x
    array([10,  9,  8,  7,  6,  5,  4,  3,  2])

●x[[3, 3, 1, 8]]:获取x中的下标为3、3、1、8的4个元素,组成一个新的数组。

●x[[3, 3, -3, 8]]:下标可以是负数,-3表示取倒数第3个元素(从1开始计数)。

    a = x[[3, 3, 1, 8]]
    b = x[[3, 3, -3, 8]]
         a             b      
    ------------  ------------
    [7, 7, 9, 2]  [7, 7, 4, 2]

下面修改b[2]的值,但是由于它和x不共享内存,因此x的值不变:

    b[2] = 100
             b                             x                  
    --------------------  ------------------------------------
    [  7,   7, 100,   2]  [10,  9,  8,  7,  6,  5,  4,  3,  2]

整数序列下标也可以用来修改元素的值:

    x[[3,5,1]] = -1, -2, -3
    x
    array([10, -3,  8, -1,  6, -2,  4,  3,  2])

当使用整数数组作为数组下标时,将得到一个形状和下标数组相同的新数组,新数组的每个元素都是用下标数组中对应位置的值作为下标从原数组获得的值。当下标数组是一维数组时,结果和用列表作为下标的结果相同:

    x = np.arange(10,1,-1)
    x[np.array([3,3,1,8])]
    array([7, 7, 9, 2])

而当下标是多维数组时,得到的也是多维数组:

    x[np.array([[3,3,1,8],[3,3,-3,8]])]
    array([[7, 7, 9, 2],
           [7, 7, 4, 2]])

可以将上述操作理解为:先将下标数组展平为一维数组,并作为下标获得一个新的一维数组,然后将其形状修改为下标数组的形状:

    x[[3,3,1,8,3,3,-3,8]].reshape(2,4) # 改变数组形状
    array([[7, 7, 9, 2],
           [7, 7, 4, 2]])

当使用布尔数组b作为下标存取数组x中的元素时,将获得数组x中与数组b中True对应的元素。使用布尔数组作为下标获得的数组不和原始数组共享数据内存,注意这种方式只对应于布尔数组,不能使用布尔列表。

    x = np.arange(5,0,-1)
    x
    array([5, 4, 3, 2, 1])

布尔数组中下标为0,2的元素为True,因此获取x中下标为0, 2的元素:

    x[np.array([True, False, True, False, False])]
    array([5, 3])

如果是布尔列表,就把True当作1,把False当作0,按照整数序列方式获取x中的元素:

    x[[True, False, True, False, False]]
    array([4, 5, 4, 5, 5])

在NumPy 1.10之后的版本中,布尔列表会被当作布尔数组,因此上面的运行结果会变成array([5, 3])。

布尔数组的长度不够时,不够的部分都当作False:

    x[np.array([True, False, True, True])]
    array([5, 3, 2])

布尔数组的下标也可以用来修改元素:

    x[np.array([True, False, True, True])] = -1, -2, -3 
    x
    array([-1,  4, -2, -3,  1])

布尔数组一般不是手工产生,而是使用布尔运算的ufunc函数产生,关于ufunc函数请参照下一节的介绍。下面我们举一个简单的例子说明布尔数组下标的用法:

    x = np.random.randint(0, 10, 6) # 产生一个长度为6,元素值为0到9的随机整数数组
            x                             x > 5                   
    ------------------  ------------------------------------------
    [8, 1, 5, 6, 2, 7]  [ True, False, False,  True, False,  True]

表达式x > 5将数组x中的每个元素和5进行大小比较,得到一个布尔数组,True表示x中对应的值大于5。我们可以使用x > 5所得到的布尔数组收集x中所有大于5的数值:

    x[x > 5]
    array([8, 6, 7])