代码之家  ›  专栏  ›  技术社区  ›  BRz

优化其中一个参数为数组的函数

  •  -1
  • BRz  · 技术社区  · 6 年前

    我想通过改变参数来优化函数,其中两个参数实际上是数组。我试过了

    ...
    # initial parameters
    params0 = np.array([p1, p2, ... , p_array1, p_array2])
    p_min = minimize(myfunc, params0, args)
    ...
    

    其中pj是标量,p_array1和p_array2是长度相同的数组,但这给了我一个错误的说法

    ValueError: setting an array element with a sequence.
    

    我还尝试将p_array1和p_array2作为标量传递到myfunc中,然后从myfunc中的这两个数组中创建预先确定的数组(例如设置p_array1=p_array1*np.arange(6)和类似的p_array2),以消除错误,但我不希望它们被预先确定——相反,我希望“最小化”以确定它们应该是什么。

    有没有什么方法可以让我利用Scipy的一个优化函数而不产生这个错误,同时仍然保持p_array1和p_array2为数组而不是标量?

    编辑

    抱歉说得太宽泛了,以下是我的代码:

    笔记 :“myfunc”实际上是 范数余 .

    import pandas as pd
    import numpy as np
    
    def f(yvec, t, a, b, c, d, M, theta):
        # the system of ODEs to be solved
        x, y = yvec
        dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
        return dydt
    
    ni = 3 # the number of periodic forcing functions to add to the DE system
    M = 0.56*np.random.rand(ni) # the initial amplitudes of forcing functions
    theta = np.pi/6*np.arange(ni) # the initial coefficients of the forcing functions
    
    # initialize the parameters
    params0 = [0.75, 0.23, 1.0, 0.2, M, theta]
    
    # grabbing the data to be used later
    data = pd.read_csv('data.csv')
    y_data = data['Y']
    
    N = y_data.shape[0] #20
    t = np.linspace(0, N, N) # array of t values to integrate over
    yvec0 = [0.3, 0.34] # initial conditions for x and y respectively
    
    def norm_residual(params, *args):
        """
        Computes the L^2 norm of the residual of y and the data (y as defined above).
        Input:    params = array of parameters (scalars or arrays) for the DE system
                  args = other arguments to pass into the function f or to use
                       to compute the residual.
        Output: err = L^2 error of the solution vector (scalar).
        """
        data, yvec0, t = args
        a, b, c, d, M, theta = params
        sol = odeint(f, yvec0, t, args=(a, b, c, d, M, theta))
        x = sol[:, 0]; y = sol[:, 1]
        res = data - y
        err = np.linalg.norm(res, 2)
        return err
    
    from scipy.optimize import minimize
    
    p_min = minimize(norm_residual, params0, args=(y_data, yvec0, t))
    print(p_min)
    

    还有追踪

    Traceback (most recent call last):
      File "model_ex_1.py", line 62, in <module>
        p_min = minimize(norm_residual, params0, args=(y_anom, yvec0, t))
      File "/usr/lib/python2.7/dist-packages/scipy/optimize/_minimize.py", line 354, in minimize
        x0 = np.asarray(x0)
      File "/usr/lib/python2.7/dist-packages/numpy/core/numeric.py", line 482, in asarray
        return array(a, dtype, copy=False, order=order)
    ValueError: setting an array element with a sequence.
    
    3 回复  |  直到 6 年前
        1
  •  0
  •   Robert Dixon    6 年前

    如果其他元素是标量,则不能将列表放入numpy数组中。

    >>> import numpy as np
    >>> foo_array = np.array([1,2,3,[5,6,7]])
    Traceback (most recent call last):
      File "<pyshell#1>", line 1, in <module>
        foo_array = np.array([1,2,3,[5,6,7]])
    ValueError: setting an array element with a sequence.
    
        2
  •  0
  •   user3294904    6 年前

    如果你发帖的话会很有帮助 myfunc 但你可以做到-

    def foo():
        return [p0,p1,p2..pn]
    
    params0 = numpy.array([foo(), p_array1, p_array2])
    p_min = minimize(myfunc, params0, args) 
    

    或者来自 Multiple variables in SciPy's optimize.minimize

    import scipy.optimize as optimize
    
    def f(params):
        # print(params)  # <-- you'll see that params is a NumPy array
        a, b, c = params # <-- for readability you may wish to assign names to the component variables
        return a**2 + b**2 + c**2
    
    initial_guess = [1, 1, 1]
    result = optimize.minimize(f, initial_guess)
    if result.success:
        fitted_params = result.x
        print(fitted_params)
    else:
        raise ValueError(result.message)
    
        3
  •  0
  •   BRz    6 年前

    我想出来了!我找到的解决办法是改变

    params0 = [0.75, 0.23, 1.0, 0.2, M, theta]
    

    第6行到

    params0 = np.array([ 0.75, 0.23, 1.0, 0.2, *M, *theta], dtype=np.float64)
    

    在我的功能定义中,我的颂歌系统需要解决,而不是

    def f(yvec, t, a, b, c, d, M, theta):
        x, y = yvec
        dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
        return dydt
    

    我现在有了

    def f(yvec, t, myparams):
        x, y = yvec
        a, b, c, d = myparams[:4]
        ni = (myparams[4:].shape[0])//2 # halved b/c M and theta are of the same shape
        M = myparams[4:ni+4]
        theta = myparams[ni+4:]
        dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
        return dydt
    

    笔记 :我必须为“params0”添加“dtype=np.float64”,因为我得到了错误

    AttributeError: 'numpy.float64' object has no attribute 'cos'
    

    当我没有它的时候,“cos”似乎不知道如何处理“ndarray”对象。可以找到解决方法 here .

    谢谢大家的建议!