2013-10-30 22 views
7

es wie Sortierung numpy strukturiert und Rekord-Arrays von einer einzigen Spalte sieht viel langsamer als eine Art auf einem ähnlichen eigenständigen Array tun:Arrays numpy strukturiert und Rekord Sortierung ist sehr langsam

In [111]: a = np.random.rand(1e4) 

In [112]: b = np.random.rand(1e4) 

In [113]: rec = np.rec.fromarrays([a,b]) 

In [114]: timeit rec.argsort(order='f0') 
100 loops, best of 3: 18.8 ms per loop 

In [115]: timeit a.argsort() 
1000 loops, best of 3: 891 µs per loop 

Es gibt eine marginale Verbesserung die strukturierte Anordnung verwendet wird, aber es ist nicht dramatisch:

In [120]: struct = np.empty(len(a),dtype=[('a','f8'),('b','f8')]) 

In [121]: struct['a'] = a 

In [122]: struct['b'] = b 

In [124]: timeit struct.argsort(order='a') 
100 loops, best of 3: 15.8 ms per loop 

Dies zeigt an, dass es möglicherweise schneller einen Index Array von argsort zu erstellen und dann, dass die einzelnen Felder neu anordnen verwenden. Dies ist OK, außer dass ich mit sehr großen Arrays zu tun habe und es vermeiden möchte, Daten so viel wie möglich zu kopieren. Gibt es einen effizienteren Weg, der mir fehlt?

Antwort

3

Als Jaime habe gesagt, Sie können argsort verwenden, um das Record-Array zu sortieren.

inds = np.argsort(rec['f0']) 

Und take eine Kopie

np.take(rec, inds, out=rec) 
+2

Der einzige Grund dafür ist, dass 'np.take' eine Kopie erstellt, wenn Sie einen 'out'-Parameter angeben und den Modus' mode' im Standard '' raise''-Zustand belassen. Sie können [an der Quelle] suchen (https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/item_selection.c#L99). Wenn Sie einen anderen 'Modus' verwenden, wird es keine Kopie geben, aber die Ausgabe wird Müll sein, wobei einige Werte mehrere Male wiederholt werden und andere ganz fehlen. – Jaime

4

Was Sie verlangsamen ist die Verwendung von order, nicht die Tatsache, dass Sie ein Record-Array haben. Wenn Sie mit einem einzigen Feld sortieren möchten, tun Sie es wie folgt aus:

In [12]: %timeit np.argsort(rec['f0']) 
1000 loops, best of 3: 829 us per loop 

Sobald order verwendet wird, die Leistung geht nach Süden, egal wie viele Felder, die Sie sortieren möchten:

In [16]: %timeit np.argsort(rec, order=['f0']) 
10 loops, best of 3: 27.9 ms per loop 

In [17]: %timeit np.argsort(rec, order=['f0', 'f1']) 
10 loops, best of 3: 28.4 ms per loop 
+0

Aha machen zu vermeiden, verwenden! Ich habe mir gedacht, dass die Bestellung die np.argsort() unter der Haube hat, aber ich glaube nicht? – Rok

+1

aber tatsächlich löst dies nicht das Problem des Kopierens der Daten - es erfordert, dass ich die Indizes übergebe, die von argsort zurückgegeben werden, was zu einer Kopie führen wird. – Rok