web-dev-qa-db-fra.com

scipy.optimize.leastSQ avec des contraintes liées

Je recherche une routine d'optimisation à Scipy/Numpy, qui pourrait résoudre un problème de type non linéaire de moindres carrés (par exemple, ajustement une fonction paramétrique à un ensemble de données volumineux) mais y compris les limites et les contraintes (p. Ex. Minima et Maxima pour que les paramètres soient. optimisé). Pour le moment, j'utilise le python version de mpfit (traduit de l'IDL ...): Ceci n'est clairement pas optimal bien que cela fonctionne très bien.

Une routine efficace en python/scipe/etc pourrait être géniale d'avoir! Toute entrée est la bienvenue ici :-)

merci!

24
user1293231

sciped.optimize.least_squares dans SciPy 0,17 (janvier 2016) Traite les limites; Utilisez cela, pas ce piratage.


Les contraintes liées peuvent facilement être faites quadratiques et minimisées à la moindreqq avec le reste.
[.____] dire que vous voulez minimiser une somme de 10 carrés σ f_i (p) ^ 2, donc votre fonction de fonctionnement (p) est donc un 10 vecteur [f0 (p) ... F9 (p)],
[.____] et aussi vouloir 0 <= p_i <= 1 pour 3 paramètres.
[.
[.____] Si nous donnons leastsq le vecteur 13 long

[ f0(p), f1(p), ... f9(p), w*tub(p0), w*tub(p1), w*tub(p2) ]

avec W = SOIT 100, il minimisera la somme des carrés du lot: les baignoires vont contraindre 0 <= p <= 1. Général lo <= p <= hi est similaire.
[.____] Le code suivant est juste une enveloppe qui fonctionne leastsq avec par exemple. un tel vecteur de 13 long à minimiser.

# leastsq_bounds.py
# see also test_leastsq_bounds.py on Gist.github.com/denis-bz

from __future__ import division
import numpy as np
from scipy.optimize import leastsq

__version__ = "2015-01-10 jan  denis"  # orig 2012


#...............................................................................
def leastsq_bounds( func, x0, bounds, boundsweight=10, **kwargs ):
    """ leastsq with bound conatraints lo <= p <= hi
    run leastsq with additional constraints to minimize the sum of squares of
        [func(p) ...]
        + boundsweight * [max( lo_i - p_i, 0, p_i - hi_i ) ...]

    Parameters
    ----------
    func() : a list of function of parameters `p`, [err0 err1 ...]
    bounds : an n x 2 list or array `[[lo_0,hi_0], [lo_1, hi_1] ...]`.
        Use e.g. [0, inf]; do not use NaNs.
        A bound e.g. [2,2] pins that x_j == 2.
    boundsweight : weights the bounds constraints
    kwargs : keyword args passed on to leastsq

    Returns
    -------
    exactly as for leastsq,
http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.leastsq.html

    Notes
    -----
    The bounds may not be met if boundsweight is too small;
    check that with e.g. check_bounds( p, bounds ) below.

    To access `x` in `func(p)`, `def func( p, x=xouter )`
    or make it global, or `self.x` in a class.

    There are quite a few methods for box constraints;
    you'll maybe sing a longer song ...
    Comments are welcome, test cases most welcome.

"""
    # Example: test_leastsq_bounds.py

    if bounds is not None  and  boundsweight > 0:
        check_bounds( x0, bounds )
        if "args" in kwargs:  # 8jan 2015
            args = kwargs["args"]
            del kwargs["args"]
        else:
            args = ()
#...............................................................................
        funcbox = lambda p: \
            np.hstack(( func( p, *args ),
                        _inbox( p, bounds, boundsweight ))) 
    else:
        funcbox = func
    return leastsq( funcbox, x0, **kwargs )


def _inbox( X, box, weight=1 ):
    """ -> [tub( Xj, loj, hij ) ... ]
        all 0  <=>  X in box, lo <= X <= hi
    """
    assert len(X) == len(box), \
        "len X %d != len box %d" % (len(X), len(box))
    return weight * np.array([
        np.fmax( lo - x, 0 ) + np.fmax( 0, x - hi )
            for x, (lo,hi) in Zip( X, box )])

# def tub( x, lo, hi ):
#     """ \___/  down to lo, 0 lo .. hi, up from hi """
#     return np.fmax( lo - x, 0 ) + np.fmax( 0, x - hi )

#...............................................................................
def check_bounds( X, box ):
    """ print Xj not in box, loj <= Xj <= hij
        return nr not in
    """
    nX, nbox = len(X), len(box)
    assert nX == nbox, \
        "len X %d != len box %d" % (nX, nbox)
    nnotin = 0
    for j, x, (lo,hi) in Zip( range(nX), X, box ):
        if not (lo <= x <= hi):
            print "check_bounds: x[%d] %g is not in box %g .. %g" % (j, x, lo, hi)
            nnotin += 1
    return nnotin
22
denis

scipey a plusieurs routines d'optimisation contrainte à Scipire.Optimize. La variante contrainte des moindres carrés est sciped.optimize.fmin_slsqp

9
matt

La capacité de résoudre les problèmes non linéaires des moindres carrés avec les limites, de manière optimale que le MPFIT, a longtemps été manquante de Scipey.

Cette fonctionnalité très demandée a finalement été introduite dans SciPy 0.17, avec la nouvelle fonction SciPy.Optimize.Least_squares .

Cette nouvelle fonction peut utiliser un algorithme de région de confiance appropriée pour faire face aux contraintes liées et procéder à une utilisation optimale de la nature des squares de la fonction non linéaire à optimiser.

Notes:

La solution proposée par @denis a le problème majeur de l'introduction d'une "fonction de baignoire" discontinue. Cela rend le scipy.optimize.leastsq Optimisation, conçue pour des fonctions lisses, très inefficaces et éventuellement instable, lorsque la frontière est franchie.

L'utilisation de scipy.optimize.minimize avec method='SLSQP' (comme @f_ficarola suggéré) ou scipy.optimize.fmin_slsqp (comme @matt suggéré), avez le problème majeur de ne pas utiliser la nature somme de la fonction à minimiser. Ces fonctions sont conçues à la fois pour minimiser les fonctions scalaires (true également pour FMIN_SLSQP, malgré le nom trompeur). Ces approches sont moins efficaces et moins précises qu'elles peuvent être correctes.

4
divenex

Regardez: http://lmfit.github.io/lmfit-py/ , il devrait résoudre votre problème.

3
tillsten