【问题标题】:Dynamically choose argument for which to minimize a function in python using scipy.optimize使用 scipy.optimize 动态选择在 python 中最小化函数的参数
【发布时间】:2015-11-04 06:38:33
【问题描述】:

我有一个将变量列表作为参数的函数,我想使用 scipy.optimize.minimize 最小化这个函数。
问题是它是在运行时决定参数列表中的哪个变量应该进行最小化。所有其他变量都将获得一个固定值。

举个例子说明一下:

a = 1
c = 1.1
d = -1.2

def func( b ):
    return function_to_minimize( array=[a,b,c,d] )

sol = scipy.optimize.minimize( func, [b0], args=(a,c,d) )

这可行,但是,可能是 bcd 是已知的,我想优化 a 以找到最小解决方案。

更复杂的是,列表的长度也是未知的。这意味着可能存在变量efg,...等等。

实际符号如下。 None 是应该优化的元素。

array = [1, 1.1, None, -0.5, 4]

def func(arr):
    return function_to_minimize(arr)

startvalue = 1.0
sol = scipy.optimize.minimize( func, [startvalue], args='Array without None' )

有没有办法告诉 scipy.optimize.minimize 优化哪个元素?有没有我可以做的聪明的 lambda 技巧?

非常感谢您的帮助!

【问题讨论】:

    标签: python scipy


    【解决方案1】:

    如您所知,要最小化的函数会根据参数的不同而变化 给出。所以我们需要编写一些动态定义函数的代码。 一种方法是定义一个模板字符串,做一些字符串格式化 根据给定的参数修改模板,然后使用exec 定义函数。这有一些优先级——标准库使用这个technique to define namedtuples

    例如,如果我们希望最小化的表达式是

    4*(b-a)**2 + 5*(c-d)**2
    

    那么你可以使用

    import textwrap
    import scipy.optimize as optimize
    
    def make_model(*fixed):
        template = textwrap.dedent("""
            def func(variable, {fixed}):
                {variable} = variable
                return 4*(b-a)**2 + 5*(c-d)**2
            """)
        variable = set(('a', 'b', 'c', 'd')).difference(fixed)
        ns = dict()
        funcstr = template.format(variable=', '.join(variable), fixed=', '.join(fixed))
        print(funcstr)  # comment out if you don't want to see the function
        exec funcstr in ns
        return ns['func']
    
    def solve(initial_guess, **givens):
        fixed = tuple(givens.keys())
        vals = tuple(givens.values())
        sol = optimize.minimize(make_model(*fixed), initial_guess, args=vals)
        return sol
    
    print(solve(initial_guess=1, a=1, c=1.1, d=-1.2))
    

    产生

    def func(variable, a, c, d):
        b = variable
        return 4*(b-a)**2 + 5*(c-d)**2
    
       status: 0
      success: True
         njev: 1
         nfev: 3
     hess_inv: array([[1]])
          fun: array([ 26.45])
            x: array([ 1.])
      message: 'Optimization terminated successfully.'
          jac: array([ 0.])
          nit: 0
    

    print(solve(initial_guess=(1, 1), a=1, c=1.1))
    

    产量

    def func(variable, a, c):
        b, d = variable
        return 4*(b-a)**2 + 5*(c-d)**2
    
       status: 0
      success: True
         njev: 3
         nfev: 12
     hess_inv: array([[1, 0],
           [0, 1]])
          fun: 2.4611848645596973e-16
            x: array([ 0.99999999,  1.1       ])
      message: 'Optimization terminated successfully.'
          jac: array([  1.19209279e-08,   2.88966118e-08])
          nit: 1
    

    【讨论】:

    • 哇,这已经解决了大部分问题,谢谢!我将尝试使其适应未知数量的变量。非常感谢!
    【解决方案2】:

    我只是想使用列表arr作为单个输入来提供unutbu's answer关于未知数量的变量的适配,其中适合的参数设置为None

    最小化fm 的函数是一个虚拟函数,只是尝试使用numpy.std 最小化数组的标准差。

    它看起来有点笨重,也不是很pythonesque,但它确实有效。

    import textwrap
    import scipy.optimize as optimize
    
    
    def make_model(n,*fixed):
        template = textwrap.dedent("""
            import numpy as np
            def fm(arr):
                return np.std(arr)
            def func(variable, {fixed}):
                {variable} = variable
                return fm(["""+",".join(["a"+str(i) for i in range(n)])+"""])
            """)
        settuple = tuple(['a'+str(i) for i in range(n)])
        variable = set(settuple).difference(fixed)
        ns = dict()
        funcstr = template.format(variable=', '.join(variable), fixed=', '.join(fixed))
        print(funcstr)  # comment out if you don't want to see the function
        exec funcstr in ns
        return ns['func']
    
    
    def solve(initial_guess, n, **givens):
        fixed = tuple(givens.keys())
        vals = tuple(givens.values())
        sol = optimize.minimize(make_model(n,*fixed), initial_guess, args=vals)
        return sol
    
    
    arr = [1, 1.1, None, -0.5, 4, 3]
    
    s = ""
    for i,a in enumerate(arr):
        if a is not None:
            s+=", a"+str(i)+"="+str(a)
    
    print "print(solve(initial_guess=1, n="+str(len(arr))+s+"))"  # comment out if you don't want to see the function       
    exec "print(solve(initial_guess=1, n="+str(len(arr))+s+"))"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-23
      • 2014-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-25
      • 2019-10-13
      • 1970-01-01
      相关资源
      最近更新 更多