2012-07-24 12 views
6

Ich möchte ein Array b zu der Form übertragen, die es nehmen würde, wenn es in einer arithmetischen Operation mit einem anderen Array a wäre. Wenn a.shape = (3,3) und b ein Skalar ist, möchte ich ein Array mit der Form (3,3) erhalten, das mit dem Skalar gefüllt ist.Gibt es eine bessere Möglichkeit, Arrays zu übertragen?

Eine Möglichkeit, dies zu tun ist, wie folgt aus:

>>> import numpy as np 
>>> a = np.arange(9).reshape((3,3)) 
>>> b = 1 + a*0 
>>> b 
array([[1, 1, 1], 
     [1, 1, 1], 
     [1, 1, 1]]) 

Obwohl dies praktisch funktioniert, kann ich nicht helfen, aber das Gefühl, es ist ein bisschen seltsam aussieht, und würde nicht auf der Suche offensichtlich an jemand anderen bei der Code was ich versuchte zu tun.

Gibt es eine elegantere Möglichkeit, dies zu tun? Ich habe die Dokumentation für np.broadcast angeschaut, aber es ist um Größenordnungen langsamer.

In [1]: a = np.arange(10000).reshape((100,100)) 

In [2]: %timeit 1 + a*0 
10000 loops, best of 3: 31.9 us per loop 

In [3]: %timeit bc = np.broadcast(a,1);np.fromiter((v for u, v in bc),float).reshape(bc.shape) 
100 loops, best of 3: 5.2 ms per loop 

In [4]: 5.2e-3/32e-6 
Out[4]: 162.5 

Antwort

7

Wenn Sie nur ein Array mit einem Skalar füllen wollen, ist fill wahrscheinlich die beste Wahl. Aber es klingt, als wolltest du etwas Generalisierteres. Anstatt broadcast zu verwenden, können Sie broadcast_arrays verwenden, um das Ergebnis zu erhalten, das (ich denke) Sie wollen.

>>> a = numpy.arange(9).reshape(3, 3) 
>>> numpy.broadcast_arrays(a, 1)[1] 
array([[1, 1, 1], 
     [1, 1, 1], 
     [1, 1, 1]]) 

Diese verallgemeinert zu zwei beliebigen sende Formen:

>>> numpy.broadcast_arrays(a, [1, 2, 3])[1] 
array([[1, 2, 3], 
     [1, 2, 3], 
     [1, 2, 3]]) 

Es ist nicht ganz so schnell wie Ihre ufunc -basierte Methode, aber es ist immer noch auf der gleichen Größenordnung:

>>> %timeit 1 + a * 0 
10000 loops, best of 3: 23.2 us per loop 
>>> %timeit numpy.broadcast_arrays(a, 1)[1] 
10000 loops, best of 3: 52.3 us per loop 

Aber Skalare, fill ist immer noch der klare Spitzenreiter:

>>> %timeit b = numpy.empty_like(a, dtype='i8'); b.fill(1) 
100000 loops, best of 3: 6.59 us per loop 

Schließlich zeigen weitere Tests, dass der schnellste Ansatz - in einigen Fällen zumindest - von ones zu multiplizieren ist:

>>> %timeit numpy.broadcast_arrays(a, numpy.arange(100))[1] 
10000 loops, best of 3: 53.4 us per loop 
>>> %timeit (1 + a * 0) * numpy.arange(100) 
10000 loops, best of 3: 45.9 us per loop 
>>> %timeit b = numpy.ones_like(a, dtype='i8'); b * numpy.arange(100) 
10000 loops, best of 3: 28.9 us per loop 
+0

+1 für 'broadcast_arrays()'. – EOL

+0

Perfekt! Genau das habe ich gesucht. Ich bin überrascht, dass ich es nicht gesehen habe; Es ist direkt neben "Broadcast" in den Dokumenten. – user545424

+0

Wenn Sie neugierig sind, interessiert mich der Grund dafür, dass die Funktion 'scipy.ndimage.map_coordinates' die Eingabekoordinaten nicht automatisch ausstrahlt, also muss ich es manuell machen. – user545424

1

Wenn Sie nur ein Skalar zu einer beliebigen Form müssen ausgestrahlt, können Sie etwas tun:

a = b*np.ones(shape=(3,3)) 

Edit: np.tile ist allgemeiner. Sie können es verwenden, beliebige skalare/Vektor in einer beliebigen Anzahl von Dimensionen zu duplizieren:

b = 1 
N = 100 
a = np.tile(b, reps=(N, N)) 
+1

'b * np.ones()' beinhaltet * Multiplikationen *, während wir * Werte * nur kopieren müssen. 'fill()' ist sowohl geeigneter als auch schneller. – EOL

2

fill klingt wie die einfachste Art und Weise:

>>> a = np.arange(9).reshape((3,3)) 
>>> a 
array([[0, 1, 2], 
     [3, 4, 5], 
     [6, 7, 8]]) 
>>> a.fill(10) 
>>> a 
array([[10, 10, 10], 
     [10, 10, 10], 
     [10, 10, 10]]) 

EDIT: Wie @EOL weist darauf hin, Sie don‘ t brauchen arange, wenn Sie ein neues Array erstellen möchten, ist np.empty((100,100)) (oder welche Form auch immer) besser dafür.

Timings:

In [3]: a = np.arange(10000).reshape((100,100)) 
In [4]: %timeit 1 + a*0 
100000 loops, best of 3: 19.9 us per loop 

In [5]: a = np.arange(10000).reshape((100,100)) 
In [6]: %timeit a.fill(1) 
100000 loops, best of 3: 3.73 us per loop 
+0

Warum der Downvote? – Bruno

+0

Es gibt keinen Grund, 'arange()' zu verwenden: das verschwendet Zeit umsonst, da ein Array erstellt und mit Zahlen gefüllt werden muss, die nur gelöscht werden. – EOL

+1

@EOL, Ich nahm nur das Beispiel in der Frage, um ein Array zu erstellen. Es ist irrelevant für diese Frage (ich nahm an, dass das Array bereits da war und darauf wartete, dass es gefüllt wurde.) – Bruno

1

Die schnellste und sauberste Lösung, die ich weiß, ist:

b_arr = numpy.empty(a.shape) # Empty array 
b_arr.fill(b) # Filling with one value 
Verwandte Themen