pythonnumpyscipydifferential-evolution

Scipy, differential evolution


The thing is, im trying to design of fitting procedure for my purposes and want to use scipy`s differential evolution algorithm as a general estimator of initial values which then will be used in LM algorithm for better fitting. The function i want to minimize with DE is the least squares between analytically defined non-linear function and some experimental values. Point at which i stuck is the function design. As its stated in scipy reference: "function must be in the form f(x, *args) , where x is the argument in the form of a 1-D array and args is a tuple of any additional fixed parameters needed to completely specify the function"

There is an ugly example of code which i wrote just for illustrative purposes:

def func(x, *args):
    """args[0] = x
       args[1] = y"""
    result = 0
    for i in range(len(args[0][0])):
        result += (x[0]*(args[0][0][i]**2) + x[1]*(args[0][0][i]) + x[2] - args[0][1][i])**2   
    return result**0.5

if __name__ == '__main__':
    bounds = [(1.5, 0.5), (-0.3, 0.3), (0.1, -0.1)]
    x = [0,1,2,3,4]
    y = [i**2 for i in x]
    args = (x, y)
    result = differential_evolution(func, bounds, args=args)
    print(func(bounds, args))

I wanted to supply raw data as a tuple into the function but it seems that its not how its suppose to be since interpreter isn't happy with the function. The problem should be easy solvable, but i really frustrated, so advice will be much appreciated.


Solution

  • This is kinda straightforward solution which shows the idea, also code isn`t very pythonic but for simplicity i think its good enough. Ok as example we want to fit equation of a kind y = ax^2 + bx + c to a data obtained from equation y = x^2. It obvious that parameter a = 1 and b,c should equal to 0. Since differential evolution algorithm finds minimum of a function we want to find a minimum of a root mean square deviation (again, for simplicity) of analytic solution of general equation (y = ax^2 + bx + c) with given parameters (providing some initial guess) vs "experimental" data. So, to the code:

    from scipy.optimize import differential_evolution
    
    def func(parameters, *data):
    
        #we have 3 parameters which will be passed as parameters and
        #"experimental" x,y which will be passed as data
    
        a,b,c = parameters
        x,y = data
    
        result = 0
    
        for i in range(len(x)):
            result += (a*x[i]**2 + b*x[i]+ c - y[i])**2
    
        return result**0.5
    
    if __name__ == '__main__':
        #initial guess for variation of parameters
        #             a            b            c
        bounds = [(1.5, 0.5), (-0.3, 0.3), (0.1, -0.1)]
    
        #producing "experimental" data 
        x = [i for i in range(6)]
        y = [x**2 for x in x]
    
        #packing "experimental" data into args
        args = (x,y)
    
        result = differential_evolution(func, bounds, args=args)
        print(result.x)