vendredi 7 avril 2017

scipy.optimize.minimize keeps returning math error, going out of bounds

I'm using scipy.opimize.minimize to find the best fit parameters for the negative log-likelihood of a dataset (which has a given pdf). The functions for calculating the pdf and the negative log-likelihood are given below:

def density(time, x, y, z):
    w = (z/x)*mt.exp(-time/x) + ((1-z)/y)*mt.exp(-time/y)
    return w


def NLL2(params):

    sig = 0
    a, b, c = params[0], params[1], params[2]
    for i in range(0, 100):
        sig = sig - mt.log(density(xval[i], a, b, c))
    return sig

where xval is the dataset (list of 100time values between 0-10). For what it's worth, the pdf is of a double decay process.

I have been given starting values for x, y and z (stored in a list called "initial_guesses" which is given to the NLL2 function as the "param" argument), and I have to find the best-fit values of x, y and z (i.e. those values which minimise NLL2 for a given dataset xval).

I try to do this with the following line of code:

initial_guesses = [1.30719636,  0.19783642,  0.25150731]

best_fit = sci.optimize.minimize(NLL2, initial_guesses, bounds = [(0.1, 20), (0.1, 20), (0.1, 1)], method = 'L-BFGS-B').x

The bounds have been chosen as what I'm "supposed" to come up with is something like [1.3, 0.2, 0.25] i.e. close to the initial values. However, when I do this, I often end up with this error message:

File "newcode2.py", line 125, in NLL2 sig = sig - mt.log(density(xval[i], x, y, z)) ValueError: math domain error

I know this is happening because the logarithm is being taken of a negative value, but the bounds I've given to the minimizer should prevent this from happening.

To investigate further, I changed the NLL2 function to the following:

def NLL2(params):

    sig = 0
    a, b, c = params[0], params[1], params[2]
    for i in range(0, 100):
        if density(xval[i], a, b, c) > 0:
            sig = sig - mt.log(density(xval[i], a, b, c))
        else:
            print density(xval[i], a, b, c), xval[i], params, '\n'
    return sig

An example of what the terminal prints out now is the following:

-4.25654045048e-10 2.76533572107 [ 0.1 20. 1.00000001]

So somehow the parameters are going to the limits of the bounds that I've set, in the last case actually going over by 1e-8. This is causing the density function to return a minutely negative number, which is causing a crash.

Does anyone know how I can stop the minimizer doing this? I've also tried using the SLSQP method, but with the same problem.

I apologize if I've given too much detail, but I'm tired and I also want to give out any information which might be useful.

NB I've imported the math class as mt.




Aucun commentaire:

Enregistrer un commentaire