2017-03-20 5 views
2

Ich habe ein Optimierungsproblem, das ich in Python lösen muss. Die allgemeine Struktur istPython Least Squares für mehrere Variablen

def foo(a, b, c, d, e): 
    # do something and return one value 


def bar(a, b, c, d, e, f, g, h, i, j): 
    # do something and return one value 


def func(): 
    return foo(a, b, c, d, e) - bar(a, b, c, d, e, f, g, h, i, j) 

I least_squares Minimierung verwenden möchte und die Werte für f, g, h, i and j als Liste zurück, wo der Platz Unterschied ist das Minimum zwischen foo und bar. Ich bin nicht sicher, wie man least_squares dafür benutzt.

Ich habe dies versucht:

# Initial values f, g, h, i, j 
x0 =[0.5,0.5,0.5,0.05,0.5] 

# Constraints 
lb = [0,0,0,0,-0.9] 
ub = [1, 100, 1, 0.5, 0.9] 

x = least_squares(func, x0, lb, ub) 

Wie erhalte ich x der Rückgabewert der Liste der f, g, h, i and j Minimalwerte zu sein?

+2

hast du die 'lost_squares'-methode von' scipy' ausprobiert? Details https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.least_squares.html –

+1

@Anil_M Wie genau verwenden Sie diese Funktion ist meine Frage? – Newtt

Antwort

1

Die Art und Weise, wie Sie Ihr Problem definieren, entspricht der Maximierung bar (vorausgesetzt, dass Sie func an eine Minimierungsfunktion übergeben). Da Sie die Parameter a bis e, func nicht variieren, ist grundsätzlich der Unterschied zwischen einer Konstanten und dem Ergebnis von bar, die abgestimmt werden kann; aufgrund des negativen Vorzeichens wird versucht, maximiert zu werden, da dies dann die gesamte Funktion minimieren würde.

Ich denke, was Sie eigentlich minimieren möchten, ist der absolute Wert oder quadrierten Unterschied zwischen den beiden Funktionen. Ich zeigen, dass ein einfaches Beispiel mit dem ich davon ausgehen, dass die Funktionen nur die Summe der Parameter zurück:

from scipy.optimize import minimize 

def foo(a, b, c, d, e): 
    # do something and return one value 

    return a + b + c + d + e 

def bar(a, b, c, d, e, f, g, h, i, j): 
    # do something and return one value 
    return a + b + c + d + e + f + g + h + i + j 

def func1(x): 
    # your definition, the total difference 
    return foo(x[0], x[1], x[2], x[3], x[4]) - bar(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9]) 

def func2(x): 
    # quadratic difference 
    return (foo(x[0], x[1], x[2], x[3], x[4]) - bar(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9]))**2 

# Initial values for all variables 
x0 = (0, 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.05, 0.5) 

# Constraints 
# lb = [0,0,0,0,-0.9] 
# ub = [1, 100, 1, 0.5, 0.9] 
# for illustration, a, b, c, d, e are fixed to 0; that should of course be changed 
bnds = ((0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0., 1), (0., 100.), (0, 1), (0, 0.5), (-0.9, 0.9)) 

res1 = minimize(func1, x0, method='SLSQP', bounds=bnds) 
res2 = minimize(func2, x0, method='SLSQP', bounds=bnds) 

Dann erhalten Sie:

print res1.x 
array([ 0. , 0. , 0. , 0. , 0. , 1. , 100. , 1. , 
      0.5, 0.9]) 

und

print res1.fun 
-103.4 

Wie oben erklärt , gehen alle Parameter an die obere Grenze, um bar zu maximieren, was func minimiert.

Für die angepasste Funktion func2, erhalten Sie:

res2.fun 
5.7408853312979541e-19 # which is basically 0 

res2.x 
array([ 0.  , 0.  , 0.  , 0.  , 0.  , 
    0.15254237, 0.15254237, 0.15254237, 0.01525424, -0.47288136]) 

So, wie erwartet, für diesen einfachen Fall man die Parameter so wählen, dass der Unterschied zwischen diesen beiden Funktionen 0. Deutlich wird, die Ergebnis für Ihre Parameter ist nicht eindeutig, sie könnten auch alle 0 sein.

Ich hoffe, dass hilft, um Ihre tatsächlichen Funktionen arbeiten zu lassen.

EDIT:

Wie Sie für least_square gefragt, die auch in Ordnung (von oben Gebrauch Funktionsdefinition) arbeitet; dann die Gesamtdifferenz ist ok:

from scipy.optimize import least_squares 

lb = [0,0,0,0,0,0,0,0,0,-0.9] 
ub = [0.1,0.1,0.1,0.1,0.1,1, 100, 1, 0.5, 0.9] 
res_lsq = least_squares(func1, x0, bounds=(lb, ub)) 

Dann erhalten Sie das gleiche Ergebnis wie oben:

res_lsq.x 
array([ 1.00000000e-10, 1.00000000e-10, 1.00000000e-10, 
     1.00000000e-10, 1.00000000e-10, 1.52542373e-01, 
     1.52542373e-01, 1.52542373e-01, 1.52542373e-02, 
     -4.72881356e-01]) 

res_lsq.fun 
array([ -6.88463034e-11]) # basically 0 

Als 5-Parameter werden in diesem Problem nicht verändert werden, würde ich sie auf einen bestimmten Wert beheben und würde sie nicht an den Optimierungsaufruf übergeben.