2012-11-13 11 views
14

Ich habe eine Funktion, die eine Reihe von Parametern hat. Anstatt alle Parameter manuell einzustellen, möchte ich eine Rastersuche durchführen. Ich habe eine Liste möglicher Werte für jeden Parameter. Für jede mögliche Kombination von Parametern möchte ich meine Funktion ausführen, die die Leistung meines Algorithmus auf diese Parameter meldet. Ich möchte die Ergebnisse in einer vieldimensionalen Matrix speichern, so dass ich im Nachhinein nur den Index der maximalen Leistung finden kann, der mir wiederum die besten Parameter geben würde. Hier ist, wie der Code jetzt geschrieben:Elegante Gittersuche in Python/Numpy

param1_list = [p11, p12, p13,...] 
param2_list = [p21, p22, p23,...] # not necessarily the same number of values 
... 

results_size = (len(param1_list), len(param2_list),...) 
results = np.zeros(results_size, dtype = np.float) 

for param1_idx in range(len(param1_list)): 
    for param2_idx in range(len(param2_list)): 
    ... 
    param1 = param1_list[param1_idx] 
    param2 = param2_list[param2_idx] 
    ... 
    results[param1_idx, param2_idx, ...] = my_func(param1, param2, ...) 

max_index = np.argmax(results) # indices of best parameters! 

ich den ersten Teil behalten will, wo ich die Listen definieren, wie sie ist, da ich einfach in der Lage sein will, die Werte zu manipulieren, über die ich suche.

Ich möchte auch mit der Ergebnismatrix so bleiben, wie es ist, da ich visualisieren werde, wie die Änderung verschiedener Parameter die Leistung des Algorithmus beeinflusst.

Das Bit in der Mitte ist jedoch ziemlich repetitiv und sperrig (vor allem, weil ich viele Parameter habe, und ich möchte vielleicht Parameter hinzufügen oder entfernen), und ich denke, es sollte eine prägnantere/elegantere Art geben Um die Ergebnismatrix zu initialisieren, über alle Indizes iterieren und die entsprechenden Parameter einstellen.

Also, gibt es?

+2

sieht aus wie Sie suchen nach 'itertools.product' –

+0

Ahh, in der Tat! Dies wird die Dinge ein wenig vereinfachen! – dlants

+0

so im Wesentlichen, hier ist ein Beinahe-Duplikat: http://stackoverflow.com/questions/1316068/pythonicway-of-iterating-over-3d-array –

Antwort

8

Ich denke, scipy.optimize.brute ist, was Sie suchen.

>>> from scipy.optimize import brute 
>>> a,f,g,j = brute(my_func,[param1_list,param2_list,...],full_output = True) 

Beachten Sie, dass, wenn das full_output Argument True ist, wird das Bewertungsraster zurückgeschickt werden.

+0

Ich vereinfachte die Situation über ein bisschen. Ich berichte tatsächlich mehrere Werte als Ausgabe (mehrere Bewertungsfunktionen), so dass meine Ergebniszeile Ergebnisse [p1idx, p2idx, ...,:,:,:] = 3d Matrix der Ausgabewerte ist. Ich glaube nicht, dass ich die Bruteforce-Suche von Scipy aus nutzen kann. Ihre Lösung entspricht genau dem oben beschriebenen Problem, aber ich suche nach Möglichkeiten, diesen Code zu vereinfachen, um die Ergebnismatrix zu erstellen, ohne auf eine vorhandene Rastersuchfunktion zurückgreifen zu müssen. – dlants

+0

Ist es der Fall, dass Sie versuchen, die besten Eingabeparameter für einen von vielen skalaren Ausgaben zu finden, zB "Geben Sie mir die Eingaben, die das Ergebnis minimieren [i]", oder haben Sie eine Möglichkeit, die "Güte" zu bewerten? von allen Ergebnissen auf einmal, wie die Summe, oder l1 oder l2 Norm? –

+1

Die Werte sind Genauigkeit, Präzision und Abruf für verschiedene Objekte. Ich werde die genaue Genauigkeit innerhalb jeder Objektkategorie und über Objekte hinweg nehmen und die Präzisions- und Rückrufmaßnahmen auf verschiedene Arten kombinieren. – dlants

6

John Vinyard 's Lösung scheint richtig; aber wenn Sie nach mehr Flexibilität suchen, könnten Sie Rundfunk + vectorize verwenden. Verwenden Sie ix_ ein sendefähiges Satz von Parametern zu erzeugen, und dann diejenigen auf eine vektorisierte Version der Funktion übergeben (siehe aber Vorbehalt unten):

a, b, c = range(3), range(3), range(3) 
def my_func(x, y, z): 
    return (x + y + z)/3.0, x * y * z, max(x, y, z) 

grids = numpy.vectorize(my_func)(*numpy.ix_(a, b, c)) 
mean_grid, product_grid, max_grid = grids 

mit den folgenden Ergebnissen für mean_grid:

array([[[ 0.  , 0.33333333, 0.66666667], 
     [ 0.33333333, 0.66666667, 1.  ], 
     [ 0.66666667, 1.  , 1.33333333]], 

     [[ 0.33333333, 0.66666667, 1.  ], 
     [ 0.66666667, 1.  , 1.33333333], 
     [ 1.  , 1.33333333, 1.66666667]], 

     [[ 0.66666667, 1.  , 1.33333333], 
     [ 1.  , 1.33333333, 1.66666667], 
     [ 1.33333333, 1.66666667, 2.  ]]]) 

product grid :

array([[[0, 0, 0], 
     [0, 0, 0], 
     [0, 0, 0]], 

     [[0, 0, 0], 
     [0, 1, 2], 
     [0, 2, 4]], 

     [[0, 0, 0], 
     [0, 2, 4], 
     [0, 4, 8]]]) 

und max grid:

array([[[0, 1, 2], 
     [1, 1, 2], 
     [2, 2, 2]], 

     [[1, 1, 2], 
     [1, 1, 2], 
     [2, 2, 2]], 

     [[2, 2, 2], 
     [2, 2, 2], 
     [2, 2, 2]]]) 

Beachten Sie, dass dies möglicherweise nicht der schnellste Ansatz ist. vectorize ist praktisch, aber es ist durch die Geschwindigkeit der Funktion begrenzt, und Python-Funktionen sind langsam. Wenn Sie my_func umschreiben könnten, um numpy ufuncs zu verwenden, könnten Sie Ihre Gitter schneller erhalten, wenn Sie interessiert waren.Etwas wie folgt aus:

>>> def mean(a, b, c): 
...  return (a + b + c)/3.0 
... 
>>> mean(*numpy.ix_(a, b, c)) 
array([[[ 0.  , 0.33333333, 0.66666667], 
     [ 0.33333333, 0.66666667, 1.  ], 
     [ 0.66666667, 1.  , 1.33333333]], 

     [[ 0.33333333, 0.66666667, 1.  ], 
     [ 0.66666667, 1.  , 1.33333333], 
     [ 1.  , 1.33333333, 1.66666667]], 

     [[ 0.66666667, 1.  , 1.33333333], 
     [ 1.  , 1.33333333, 1.66666667], 
     [ 1.33333333, 1.66666667, 2.  ]]]) 
1

können Sie verwenden numpy meshgrid für diese verwenden:

import numpy as np 

x = range(1, 5) 
y = range(10) 

xx, yy = np.meshgrid(x, y) 
results = my_func(xx, yy) 

Beachten Sie, dass Ihre Funktion in der Lage sein muss, mit numpy.array s zu arbeiten.

Verwandte Themen