使用sympy lambdify和scipy进行Python优化

5

我想要最大化一个由sympy定义的函数,但是无法使其正常工作。基本思路可以概括如下:

    import sympy
    from scipy.optimize import minimize
    from sympy.utilities.lambdify import lambdify

    a,b,G = sympy.symbols('a b G')
    func = (G - a)**2 + b
    my_func = lambdify((G,a,b), -1*func)
    results = minimize(my_func,[0.1,0.1,0.1])

如果我定义一个单变量函数,那么这段代码可以工作,但只要有多于一个变量,我就会收到以下错误信息。

    TypeError: <lambda>() takes exactly 3 arguments (1 given)

有人可以帮我确定出了哪里问题吗?


1
“minimize” 函数期望函数是“单参数”的,也就是说你传入的是一个单一的对象。然而,这个单一的对象可以是一个列表。你确定你需要 sympy 吗?Scipy(而不是 sympy)处理的是数值计算,而不是符号计算... - Dair
1
@Dair 是的,我需要使用sympy来方便地定义目标函数,否则我将很难定义它。我知道它的范围仅限于数值计算,但您是否知道是否有一种方法可以将符号函数转换为lambda函数,以便可以将其传递给scipy.minimize? - user3821012
我想不出一种符号化的方法,但非符号化的方法也不错:func = lambda x: (x[0] - x[1])**2 + x[2] - Dair
这个有帮助吗?链接 - lhcgeneva
不,我没有计算雅可比矩阵。上面的代码只是举了一个例子。我实际上正在优化一个符号函数。我有一个超长的符号函数(有20个变量),需要找到最大化函数的值(对于这20个变量)。 - user3821012
显示剩余3条评论
1个回答

5

正如 @Dair 指出的那样,sympy的lambdify通常需要多个参数,而scipy只需要一个参数,即包含每个变量值的列表(或数组)。因为我的目标函数最方便使用sympy定义,所以我需要找到一种方法来解决sympy和scipy的不兼容性。

@lhcgeneva指出了类似问题的答案。这个答案不能方便地处理大量独立变量,特别是当独立变量的数量可以改变时,需要重新定义“向量化”版本的目标函数。然而,受到这篇文章的启发,我想出了以下使用*tuple()的解决方案:

    import sympy
    from scipy.optimize import minimize
    from sympy.utilities.lambdify import lambdify

    a,b,G = sympy.symbols('a b G')
    func = -1*((G - a)**2 + b)
    my_func = lambdify((G,a,b), func)

    def my_func_v(x):
        return my_func(*tuple(x))

    results = minimize(my_func_v,[0.1,0.1,0.1])

在我给出的例子中,使用*tuple()似乎是不必要的,但对于我想解决的问题来说,它可以节省很多麻烦。这里有一个更类似于我想解决的问题的示例。
NUM_VAR = 10
x = np.array(sympy.symbols('x0:%d'%NUM_VAR))
func = np.sum((x-1)**2)
my_func = lambdify(x, func)


def my_func_v(x):
    return my_func(*tuple(x))

results = minimize(my_func_v,np.zeros(NUM_VAR))

这个*tuple()可以帮我避免写出像以下这样的所有x元素的代码(对于NUM_VAR=10的情况):
def my_func_v(x):
    return my_func(x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9])

此外,当 NUM_VAR 改变时,我们不需要修改 my_func_v。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接