Minimising functions with optimize

SciPy · Essentials · 11 min

Fitting models, calibrating parameters and solving design problems all reduce to minimising a function.

scipy.optimize finds inputs that make a function as small as possible. Maximise by minimising the negative.

For one variable, optimize.minimize_scalar(f) uses Brent's method; pass bounds=(a, b) with method="bounded" to search an interval.

For several variables, optimize.minimize(fun, x0) needs:

  • fun(x): takes a 1-D array of parameters and returns a float,
  • x0: a starting guess of the same shape,
  • optionally args=(...): extra fixed arguments passed to fun,
  • optionally method: the default for unconstrained problems is "BFGS"; "Nelder-Mead" needs no gradients and tolerates noise; "L-BFGS-B" handles bounds and scales to many variables.

The result is an OptimizeResult. Always check res.success and res.message before using res.x; res.fun is the minimum value and res.nfev counts function evaluations.

These are local optimisers: they walk downhill from x0 and stop in the nearest valley. For non-convex functions, try several starting points or a global method. Scale matters too: if one parameter is around 1e-6 and another around 1e3, rescale them to similar magnitudes or the optimiser struggles.

Gradients speed things up a lot; when you can, pass jac= with a function returning the gradient.

Example

import numpy as np
from scipy import optimize

res1 = optimize.minimize_scalar(lambda x: (x - 2) ** 2 + 1)
print(round(res1.x, 4), round(res1.fun, 4))   # 2.0 1.0

def rosen(p, a=1.0):                  # classic banana-shaped valley
    x, y = p
    return (a - x) ** 2 + 100 * (y - x ** 2) ** 2

res = optimize.minimize(rosen, x0=np.array([-1.0, 2.0]), method="BFGS")
print(res.success, res.x.round(4))    # True [1. 1.]
print(res.nfev > 0, round(res.fun, 8))  # True 0.0

res = optimize.minimize(rosen, x0=[0, 0], args=(2.0,), method="Nelder-Mead")
print(res.x.round(3))                 # [2. 4.] (minimum moves with a=2)

Remember

  • minimize(fun, x0) with fun taking a 1-D array and returning a float
  • Check res.success before trusting res.x
  • Local optimisers find the nearest minimum; try several starts on non-convex problems

Watch out for

  • Returning an array from the objective instead of a single float.

Check yourself

  1. minimize returns res.success == False. What should you do first?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.scipy.org/doc/scipy/tutorial/optimize.html