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

2.2.5 ufunc的方法

ufunc函数对象本身还有一些方法函数,这些方法只对两个输入、一个输出的ufunc函数有效,其他的ufunc对象调用这些方法时会抛出ValueError异常。

reduce()方法和Python的reduce()函数类似,它沿着axis参数指定的轴对数组进行操作,相当于将<op>运算符插入到沿axis轴的所有元素之间:<op>.reduce(array, axis=0, dtype=None)。例如:

    r1 = np.add.reduce([1, 2, 3])  # 1 + 2 + 3
    r2 = np.add.reduce([[1, 2, 3], [4, 5, 6]], axis=1)  # (1+2+3),(4+5+6)
    r1     r2   
    --  --------
    6   [ 6, 15]

accumulate()方法和reduce()类似,只是它返回的数组和输入数组的形状相同,保存所有的中间计算结果:

    a1 = np.add.accumulate([1, 2, 3])
    a2 = np.add.accumulate([[1, 2, 3], [4, 5, 6]], axis=1)
        a1           a2      
    ---------  --------------
    [1, 3, 6]  [[ 1,  3,  6],
                [ 4,  9, 15]]

reduceat()方法计算多组reduce()的结果,通过indices参数指定一系列的起始和终止位置。它的计算有些特别,让我们通过例子详细解释一下:

    a = np.array([1, 2, 3, 4])
    result = np.add.reduceat(a, indices=[0, 1, 0, 2, 0, 3, 0])
    result
    array([ 1,  2,  3,  3,  6,  4, 10])

对于indices参数中的每个元素都会计算出一个值,因此最终的计算结果和indices参数的长度相同。结果数组result中除最后一个元素之外,都按照如下计算得出:

    if indices[i] < indices[i+1]:
        result[i] = <op>.reduce(a[indices[i]:indices[i+1]])
    else:
        result[i] = a[indices[i]]

而最后一个元素如下计算:

    <op>.reduce(a[indices[-1]:])

因此在上面的例子中,数组result的每个元素按照如下计算得出:

        1 : a[0] -> 1
        2 : a[1] -> 2
        3 : a[0] + a[1] -> 1 + 2
        3 : a[2] -> 3
        6 : a[0] + a[1] + a[2] ->  1 + 2 + 3 = 6
        4 : a[3] -> 4
        10: a[0] + a[1] + a[2] + a[4] -> 1 + 2 + 3 + 4 = 10

可以看出result[::2]和a相等,而result[1::2]和np.add.accumulate(a)相等。

ufunc函数对象的outer()方法等同于如下程序:

    a.shape += (1,)*b.ndim
    <op>(a,b)
    a = a.squeeze()

其中squeeze()方法剔除数组a中长度为1的轴。让我们看一个例子:

    np.multiply.outer([1, 2, 3, 4, 5], [2, 3, 4])
    array([[ 2,  3,  4],
           [ 4,  6,  8],
           [ 6,  9, 12],
           [ 8, 12, 16],
           [10, 15, 20]])

可以看出通过outer()计算的结果是如下乘法表:

    *| 2  3  4       
    ------------
    1| 2  3  4
    2| 4  6  8
    3| 6  9 12
    4| 8 12 16 
    5|10 15 20

如果将这两个数组按照等同程序一步一步地进行计算,就会发现乘法表最终是通过广播的方式计算出来的。