2016-03-27 15 views
1

Ich habe eine Python-Funktion mit einer verschachtelten For-Schleife, die Tausende Male aufgerufen wird, und ist zu langsam. Von dem, was ich online gelesen habe, sollte es eine Möglichkeit geben, es mit numpy Vektorisierung zu optimieren, so dass die Iteration in viel schneller C-Code statt Python durchgeführt wird. Aber ich habe noch nie mit Numpy gearbeitet und kann es nicht herausfinden.Optimieren Double For Loop mit NumPy

Die Funktion ist unten. Der erste Parameter ist ein 2-dimensionales Array (Liste von Listen). Der zweite Parameter ist eine Liste von Zeilen des zu überprüfenden 2D-Arrays. Der dritte Parameter ist eine Liste von Spalten des zu überprüfenden 2D-Arrays (Beachten Sie, dass die Anzahl der Zeilen nicht der Anzahl der Spalten entspricht). Der vierte Parameter ist ein Wert, mit dem Elemente des 2D-Arrays verglichen werden. Ich versuche, eine Liste zurückzugeben, die für jede Spalte eine Liste enthält, hat alle Zeilenindizes, die Elementen gleich Val entsprechen. Wie gesagt, das ist viel zu langsam und ich bin ziemlich verwirrt darüber, wie ich das vektorisieren könnte, das ist numpy.

Alle Hinweise/Anleitungen wären großartig.

BEARBEITEN

@ B.M. Danke für deine Antwort. Ich habe Ihre Lösung getrennt vom Rest meines Codes ausgeführt und mit meiner vorherigen Funktion verglichen. Wie du schon sagtest, es funktionierte viel schneller mit numpy, die meine ursprüngliche Funktion tat. Wenn es jedoch als Teil meines Codes ausgeführt wird, ist meine Lösung aus irgendeinem Grund tatsächlich langsamer. Ich musste ein wenig zu Ihrer Funktion hinzufügen und etwas von meinem vorhandenen Code modifizieren, um sie kompatibel zu machen, aber ich werde in dieser Zeit weggeworfen es sagt, dass die numpy Version schneller ist, während cProfile zeigt, dass meine ursprüngliche filter_indices Funktion schneller ist als die neue numpy one. Ich habe keine Ahnung, wie die numpy filter_indices so viel länger dauern könnten, wenn man bedenkt, dass es schneller war, wenn es getrennt vom Rest meines Codes ausgeführt wurde.

Hier ist meine ursprüngliche filter_indices ohne numpy:

def filter_indices_orig(a, data_indices, feature_set, val): 
    result_indices = [] 

    for feature_no in feature_set: 
     feature_indices = [] 

     for idx in data_indices: 
      if a[idx][feature_no] == val: 
       feature_indices.append(idx) 
     result_indices.append(feature_indices) 

    return result_indices 

Hier ist meine leicht modifizierte filter_indices mit numpy:

def filter_indices(a, data_indices, feature_set, val): 
    result_indices = {} 
    sub = a[np.meshgrid(data_indices, feature_set, indexing='ij')] 
    r, c = (sub == val).nonzero() 
    rs = np.take(data_indices, r) 
    cs = np.take(feature_set, c) 
    coords = zip(rs, cs) 

    for r, c in coords: 
     feat_indices = result_indices.get(c, []) 
     feat_indices.append(r) 
     result_indices[c] = feat_indices 

    return result_indices 

EDIT 2

Ich fand heraus, dass die numpy Lösung langsamer ist als ich Ich suche nur nach ein paar Spalten, aber es ist schneller, wenn ich nach einer großen Anzahl von Spalten suche. Leider ist sogar die Verwendung meiner ursprünglichen nicht-numpigen Lösung, wenn einige Spalten durchsucht werden, während die numpige Lösung verwendet wird, wenn eine große Anzahl von Spalten durchsucht wird, immer noch langsamer als meine ursprüngliche Lösung, was ich überhaupt nicht verstehe.

Antwort

0

hier eine Funktion, die 2-Arrays zurück, Reihen-Indizes und cols Indices der Pixel in dem Wert val in dem ausgewählten Subarray ist:

def filter_indices_numpy(a,rows,cols,val): 
     sub=a[meshgrid(rows,cols,indexing='ij')] 
     r,c = (sub==val).nonzero() 
     return take(rows,r),take(cols,c) 

Beispiel:

a=randint(0,3,(5,5)) 

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

filter_indices_numpy(a,[1,2,3],[1,2,3],0) 
#(array([1, 1, 2, 3, 3]), array([1, 3, 3, 1, 2])) 

Einige Erklärungen:

meshgrid(rows,cols,indexing='ij') sind die Indizes ausgewählter Zeilen und Spalten. sub ist das Sub-Array. r,c = (sub==val).nonzero() sind die Indizes, deren Wert val im Unterfeld ist. take(rows,r),take(cols,c) übersetzen die Indizes im Array a.

Test auf: a=randint(0,200,(1000,1000));rows=cols=arange(100)

In [4]: %timeit filter_indices(a,rows,cols,0) 
10 loops, best of 3: 23.1 ms per loop 

In [5]: %timeit filter_indices_numpy(a,rows,cols,0) 
1000 loops, best of 3: 933 µs per loop 

es etwa 25X schneller ist.