逐元素向量化

Vectorizing an element-wise

是否可以使用 NumPy(和 SciPy)对元素优化进行矢量化(或加速)?

在最抽象的意义上,我有一个函数 y,它是抛物线形的,基本上可以表示为 y=x^2+b*x+z,其中 x 是已知值的数组,我想找到一个 z使 y 的最小值恰好为零(换句话说,我想找到一个使我的抛物线只有一个零的值 z)。为此,我选择实现一个简单的类似二分法的方法。代码如下:

import numpy as np

def find_single_root():
    x = np.arange(-5, 6,0.1) # domain
    z = 1 # initial guess
    delta = 1 # initial step size
    tol = 0.001 # tolerance
    while True:
        y = x**2-5*x+z
        minimum = np.nanmin(y)
        # update z
        print(delta)
        print(z)
        if minimum > 0:
            if delta > 0:
                delta = -1*delta/2
            z += delta
        else:
            if delta < 0:
                delta = -1*delta/2
            z += delta
        # check if step is smaller than tolerance
        if np.abs(delta) < tol:
            return z

现在假设 x(v,w),我想创建一个 z 值的二维数组,其中每个值都经过优化。我现在有的是下面(注意,新的函数定义和域如下)

def find_single_root(v, w):
    x = np.arange(-5*v/w, 6*w,0.1) # domain
    ... # rest of the function

vs = np.arange(1,5)
ws = np.arange(1,5)
zs = np.zeros((len(vs),len(ws)))
for i, v in enumerate(vs):
    for j, w in enumerate(ws):
        zs[i][j] = find_single_root(v,w)

现在我只有这些简单的嵌套 for 循环,但是有什么方法可以让我以不同的方式处理这个问题或使用 NumPy 向量化来加速它吗?

当预先准确知道要执行的计算时,矢量化可能适用。喜欢"take two arrays of numbers, and multiply them pairwise"。

当计算适应给定数据时,向量化不适用。任何一种优化算法都是自适应的,因为你在哪里寻找最小值取决于函数returns。如果你有一堆函数,并且需要找到每个函数的最小值,你将不得不在循环中一次最小化它们。如果这个过程很慢,那是因为最小化一堆函数需要很长时间,而不是因为程序中有for循环

关于您的程序,我会尝试使用一些 SciPy 方法进行最小化和 root-finding。有一个函数 min_of_f(z) 可以找到给定参数 z 值的最小值,可能使用 minimize_scalar. Then feed min_of_f to a root-finding routine。这些需要多长时间可以通过它们的公差参数(xtol 和其他)来控制。


OP编辑: 我想将此归功于正确答案,但仍提供更多信息。

我最终使用 numpy.vectorize 进行矢量化而没有重构问题。尽管 numpy.vectorize 并不是为了提高性能,但在我的特定用例中,性能只是快了两倍。对问题中的原始问题应用相同的方法导致 100x100 向量几乎没有加速,所以 YMMV。

尽管由于上述答案中给出的原因,我无法从速度方面对这个问题进行矢量化处理,但能够在我的代码中使用纯矢量语法而不是嵌套 for 循环还是很有用的。