2015-04-13 10 views
10

Ich möchte numpy Arrays mit Datentyp Uint8 hinzufügen. Ich weiß, dass die Werte in diesen Arrays möglicherweise groß genug für einen Überlauf sind. So bekomme ich so etwas wie:Vermeiden Sie Überlauf beim Hinzufügen von numpy Arrays

a = np.array([100, 200, 250], dtype=np.uint8) 
b = np.array([50, 50, 50], dtype=np.uint8) 
a += b 

Jetzt ist a [150 250 44]. Statt eines Überlaufs möchte ich jedoch Werte, die für uint8 zu groß sind, maximal für uint8 zulassen. Also mein gewünschtes Ergebnis wäre [150 250 255].

Ich kann dieses Ergebnis mit dem folgenden Code erhalten:

a = np.array([100, 200, 250], dtype=np.uint8) 
b = np.array([50, 50, 50], dtype=np.uint8) 
c = np.zeros((1,3), dtype=np.uint16) 
c += a 
c += b 
c[c>255] = 255 
a = np.array(c, dtype=np.uint8) 

Das Problem ist, dass mein Arrays wirklich groß ist, um eine dritte Reihe mit einem größeren Datentyp zu schaffen könnte ein Speicherproblem sein. Gibt es eine schnelle und speichereffizientere Möglichkeit, das beschriebene Ergebnis zu erzielen?

Antwort

6

Sie können dies erreichen, indem eine dritte Reihe von dtype uint8 Erstellung, plus eine Bool Array (die zusammen mehr Speichereffizienz sind, dass eine Uint16-Array).

np.putmask ist nützlich, um ein Temp-Array zu vermeiden.

a = np.array([100, 200, 250], dtype=np.uint8) 
b = np.array([50, 50, 50], dtype=np.uint8) 
c = 255 - b # a temp uint8 array here 
np.putmask(a, c < a, c) # a temp bool array here 
a += b 

Wie jedoch @moarningsun korrekt ausführt, ein bool Array nimmt die die gleiche Menge an Speicher als uint8 Array, so ist dies nicht unbedingt hilfreich. Es ist möglich, dies zu lösen, durch die Vermeidung von mehr als ein temporären Array mit zu einem bestimmten Zeitpunkt:

a = np.array([100, 200, 250], dtype=np.uint8) 
b = np.array([50, 50, 50], dtype=np.uint8) 
b = 255 - b # old b is gone shortly after new array is created 
np.putmask(a, b < a, b) # a temp bool array here, then it's gone 
a += 255 - b # a temp array here, then it's gone 

Dieser Ansatz handelt Speicherverbrauch für die CPU.


Ein weiterer Ansatz ist es, vorberechnen alle möglichen Ergebnisse, die O (1) zusätzliche Speicher (dh unabhängig von der Größe des Arrays) sind:

c = np.clip(np.arange(256) + np.arange(256)[..., np.newaxis], 0, 255).astype(np.uint8) 
c 
=> array([[ 0, 1, 2, ..., 253, 254, 255], 
      [ 1, 2, 3, ..., 254, 255, 255], 
      [ 2, 3, 4, ..., 255, 255, 255], 
      ..., 
      [253, 254, 255, ..., 255, 255, 255], 
      [254, 255, 255, ..., 255, 255, 255], 
      [255, 255, 255, ..., 255, 255, 255]], dtype=uint8) 

c[a,b] 
=> array([150, 250, 255], dtype=uint8) 

Dieser Ansatz ist der Speicher -effizient, wenn Ihre Arrays sehr groß sind. Wiederum ist es in der Verarbeitungszeit teuer, weil es die superschnellen Ganzzahladditionen durch die langsamere 2dim-Arrayindizierung ersetzt.

ERKLÄRUNG DER SO GEHTS

Bau des c Array macht über die Verwendung eines numpy Rundfunk Trick. Hinzufügen eines Arrays von Form (N,) und Array von Form (1,N) senden beide zu (N,N)-Like, so ist das Ergebnis ein NxN-Array aller möglichen Summen. Dann schneiden wir es ab. Wir erhalten ein 2dim-Array, das erfüllt: c[i,j]=min(i+j,255) für jeden i, j.

Dann, was übrig bleibt, ist mit phantastischen Indizierung der Greifer die richtigen Werte.Arbeiten mit dem Eingang, den Sie zur Verfügung gestellt, greifen wir auf:

c[([100, 200, 250] , [50, 50, 50])] 

Der erste Index-Array zum ersten dim bezieht und die zweite auf dem zweiten dim. Somit ist das Ergebnis ein Array mit der gleichen Form wie die Indexarrays ((N,)), bestehend aus den Werten [ c[100,50] , c[200,50] , c[250,50] ].

+1

Ich wusste nichts über 'Putmask', danke dafür! Mit dieser Funktion denke ich, dass "a + = b" gefolgt von "np.putmask (a, a

+0

@moarningsun Ich denke du bist richtig. Allerdings hängt es vom Überlaufen ab, mit dem ich mich persönlich nicht wohl fühle ... – shx2

+0

@moarningsun Warum hast du deine Antwort gelöscht? Ich denke, es ist eine anständige Antwort und es funktioniert – shx2

0

Wie sei es

>>> a + np.minimum(255 - a, b) 
array([150, 250, 255], dtype=uint8) 

im Allgemeinen tun, den maximalen Wert für Ihren Datentyp immer mit

np.iinfo(np.uint8).max 
+0

@PadraicCunningham nützlich sein, es funktioniert, aber von dtype uint8, nicht uint16. Es erzeugt jedoch * drei * Temp uint8 Arrays .. – shx2

+0

@ shx2: Ich zähle nur zwei. '255 - a' und' np.minimum (255 - a, b) '. Was ist der Dritte? – user2357112

+0

@ user2357112, die 'a + ...'. Wenn OP das Ergebnis anstelle des Arrays "a" haben möchte, ist es möglich, dies zu vermeiden. – shx2

1

hier ein Weg ist:

>>> a = np.array([100, 200, 250], dtype=np.uint8) 
>>> b = np.array([50, 50, 50], dtype=np.uint8) 
>>> a+=b; a[a<b]=255 
>>> a 
array([150, 250, 255], dtype=uint8) 
1

Sie es mit Numba wirklich inplace tun können, zum Beispiel:

import numba 

@numba.jit('void(u1[:],u1[:])', locals={'temp': numba.uint16}) 
def add_uint8_inplace_clip(a, b): 
    for i in range(a.shape[0]): 
     temp = a[i] + b[i] 
     a[i] = temp if temp<256 else 255 

add_uint8_inplace_clip(a, b) 

Oder mit numexpr, zum Beispiel:

import numexpr 

numexpr.evaluate('where((a+b)>255, 255, a+b)', out=a, casting='unsafe') 

numexpr upcastsuint8 zu int32 intern, bevor Sie es wieder in diesetzenArray.

0

ist es a function in numpy dafür:

numpy.nan_to_num(x)[source]

nan Ersetzen durch Null und inf mit endlichen Zahlen.

Gibt ein Array oder einen Skalar zurück, der Not a Number (NaN) mit Null, (positiv) unendlich mit einer sehr großen Zahl und negativ unendlich mit einer sehr kleinen (oder negativen) Zahl ersetzt.

Neues Array mit der gleichen Form wie x und dtype des Elements in x mit der größten Genauigkeit.

Wenn x ungenau ist, dann wird NaN durch Null ersetzt und unendlich (-infinity) wird durch den größten (kleinsten oder negativsten) Fließkommawert ersetzt, der in den Ausgabe-dtyp passt. Wenn x nicht ungenau ist, wird eine Kopie von x zurückgegeben.

Ich bin mir nicht sicher, ob es mit uint8 arbeiten, wegen der Erwähnung Punkt in der Ausgabe von schwimmenden, aber für andere Leser kann es

+1

Ich sehe nicht, wie dies mit der Frage helfen könnte. In keinem der Arrays, die hinzugefügt werden sollen, gibt es keine NaNs oder unendliche Werte. Vielleicht fehlt mir also der Sinn Ihrer Antwort? – Thomas

+0

@Thomas hmm, vielleicht ist es anders für Integer-Typen, aber als ich das Problem mit Schwimmern, die Überläufe erschien als +/- Unendlichkeiten –

+0

@ ToshinouKyouko Ja, es ist in der Tat anders für ganze Zahlen, sie einfach überlaufen wie im Beispiel von OP. – luator