2016-03-02 14 views
16

Ich möchte wissen, wie ich ein 2D-numpy-Array mit Nullen mit Python 2.6.6 mit numpy Version 1.5.0 auffüllen kann. Es tut uns leid! Aber das sind meine Grenzen. Daher kann ich np.pad nicht verwenden. Zum Beispiel möchte ich a mit Nullen auffüllen, so dass seine Form b entspricht. Der Grund, warum ich dies tun wollen ist, so kann ich tun:Python, wie man numpy Array mit Nullen pad

b-a 

so dass

>>> a 
array([[ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.]]) 
>>> b 
array([[ 3., 3., 3., 3., 3., 3.], 
     [ 3., 3., 3., 3., 3., 3.], 
     [ 3., 3., 3., 3., 3., 3.], 
     [ 3., 3., 3., 3., 3., 3.]]) 
>>> c 
array([[1, 1, 1, 1, 1, 0], 
     [1, 1, 1, 1, 1, 0], 
     [1, 1, 1, 1, 1, 0], 
     [0, 0, 0, 0, 0, 0]]) 

Die einzige Art, wie ich dies zu tun, ist das Anhängen denken kann, aber das ist ziemlich hässlich zu sein scheint. Gibt es eine sauberere Lösung, die möglicherweise b.shape verwendet?

Bearbeiten, Vielen Dank an MSeiferts Antwort. Ich musste es sauber ein wenig, und das ist, was ich habe:

def pad(array, reference_shape, offsets): 
    """ 
    array: Array to be padded 
    reference_shape: tuple of size of ndarray to create 
    offsets: list of offsets (number of elements must be equal to the dimension of the array) 
    will throw a ValueError if offsets is too big and the reference_shape cannot handle the offsets 
    """ 

    # Create an array of zeros with the reference shape 
    result = np.zeros(reference_shape) 
    # Create a list of slices from offset to offset + shape in each dimension 
    insertHere = [slice(offsets[dim], offsets[dim] + array.shape[dim]) for dim in range(array.ndim)] 
    # Insert the array in the result at the specified offsets 
    result[insertHere] = array 
    return result 
+0

Kann ich Ihnen einen Weg vorschlagen, dies ohne Polsterung zu tun? – purpletentacle

Antwort

44

Sehr einfach, das Erstellen eines Arrays Nullen unter Verwendung des Bezugsform enthält:

result = np.zeros(b.shape) 
# actually you can also use result = np.zeros_like(b) 
# but that also copies the dtype not only the shape 

und legen Sie die Array, in dem Sie brauchen es:

result[:a.shape[0],:a.shape[1]] = a 

und voila haben Sie es gepolstert:

print(result) 
array([[ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0., 0.]]) 

können Sie auch machen es ein bisschen mehr allgemeine, wenn Sie definieren, wo Sie Ihr linkes oberes Element sollte

result = np.zeros_like(b) 
x_offset = 1 # 0 would be what you wanted 
y_offset = 1 # 0 in your case 
result[x_offset:a.shape[0]+x_offset,y_offset:a.shape[1]+y_offset] = a 
result 

array([[ 0., 0., 0., 0., 0., 0.], 
     [ 0., 1., 1., 1., 1., 1.], 
     [ 0., 1., 1., 1., 1., 1.], 
     [ 0., 1., 1., 1., 1., 1.]]) 

eingefügt werden, aber dann vorsichtig sein, dass Sie nicht über Offsets größer als erlaubt. Für x_offset = 2 zum Beispiel wird dies fehlschlagen.

Wenn Sie eine beliebige Anzahl von Dimensionen haben, können Sie eine Liste von Slices definieren, um das ursprüngliche Array einzufügen. Ich fand es interessant, etwas herumzuspielen und schuf eine Padding-Funktion, die (mit Offset) ein beliebig geformtes Array auffüllen kann, solange das Array und die Referenz die gleiche Anzahl von Dimensionen haben und die Offsets nicht zu groß sind.

def pad(array, reference, offsets): 
    """ 
    array: Array to be padded 
    reference: Reference array with the desired shape 
    offsets: list of offsets (number of elements must be equal to the dimension of the array) 
    """ 
    # Create an array of zeros with the reference shape 
    result = np.zeros(reference.shape) 
    # Create a list of slices from offset to offset + shape in each dimension 
    insertHere = [slice(offset[dim], offset[dim] + array.shape[dim]) for dim in range(a.ndim)] 
    # Insert the array in the result at the specified offsets 
    result[insertHere] = a 
    return result 

Und einige Testfälle:

import numpy as np 

# 1 Dimension 
a = np.ones(2) 
b = np.ones(5) 
offset = [3] 
pad(a, b, offset) 

# 3 Dimensions 

a = np.ones((3,3,3)) 
b = np.ones((5,4,3)) 
offset = [1,0,0] 
pad(a, b, offset) 
+0

ah sehr nett. Könnte dies auf 1d Array oder ein beliebiges n d Array verallgemeinert werden? – user2015487

+0

@ user2015487 - Sie meinen eine Funktion, die willkürliche Dimensionen oder nur die gleiche für eine andere Dimension akzeptiert? – MSeifert

4

Ich verstehe, dass Ihr Hauptproblem ist, dass Sie d=b-a aber Ihre Arrays haben unterschiedliche Größen berechnen müssen. Es besteht keine Notwendigkeit für eine Zwischen gepolsterte c

du ohne Polsterung lösen können:

import numpy as np 

a = np.array([[ 1., 1., 1., 1., 1.], 
       [ 1., 1., 1., 1., 1.], 
       [ 1., 1., 1., 1., 1.]]) 

b = np.array([[ 3., 3., 3., 3., 3., 3.], 
       [ 3., 3., 3., 3., 3., 3.], 
       [ 3., 3., 3., 3., 3., 3.], 
       [ 3., 3., 3., 3., 3., 3.]]) 

d = b.copy() 
d[:a.shape[0],:a.shape[1]] -= a 

print d 

Ausgang:

[[ 2. 2. 2. 2. 2. 3.] 
[ 2. 2. 2. 2. 2. 3.] 
[ 2. 2. 2. 2. 2. 3.] 
[ 3. 3. 3. 3. 3. 3.]] 
+0

Zutreffend, für seinen speziellen Fall muss er nicht unbedingt auffüllen, aber das ist eine der wenigen arithmetischen Operationen, bei denen Padding und Ihr Ansatz gleichwertig sind. Trotzdem nette Antwort! – MSeifert

20

NumPy 1,7 (wenn np.pad hinzugefügt wurde) jetzt ziemlich alt ist (es wurde veröffentlicht im Jahr 2013), also obwohl die Frage nach einem Weg ohne diese Funktion gefragt, ich dachte, es könnte nützlich sein zu wissen, wie das mit np.pad erreicht werden könnte.

Es ist eigentlich ziemlich einfach:

>>> import numpy as np 
>>> a = np.array([[ 1., 1., 1., 1., 1.], 
...    [ 1., 1., 1., 1., 1.], 
...    [ 1., 1., 1., 1., 1.]]) 
>>> np.pad(a, [(0, 1), (0, 1)], mode='constant') 
array([[ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0., 0.]]) 

In diesem Fall habe ich, dass 0 der Standardwert für mode='constant' ist. Aber es könnte auch explizit, indem man es in angegeben werden:

>>> np.pad(a, [(0, 1), (0, 1)], mode='constant', constant_values=0) 
array([[ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0., 0.]]) 

Nur für den Fall das zweite Argument ([(0, 1), (0, 1)]) scheint verwirrend: Jedes Listenelement (in diesem Fall Tupel) entspricht einer Dimension und Position stellt darin die Polsterung vor (erstes Element) und nach (zweites Element). So:

[(0, 1), (0, 1)] 
     ^^^^^^------ padding for second dimension 
^^^^^^-------------- padding for first dimension 

    ^------------------ no padding at the beginning of the first axis 
    ^--------------- pad with one "value" at the end of the first axis. 

In diesem Fall ist die Polsterung für die erste und die zweite Achse ist identisch, so dass man auch nur in dem 2-Tupels passieren kann:

>>> np.pad(a, (0, 1), mode='constant') 
array([[ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 1., 1., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0., 0.]]) 

Falls die Polsterung vor und nach dem IST identisch konnte man sogar das Tupel (gilt nicht für in diesem Fall aber) weglassen:

>>> np.pad(a, 1, mode='constant') 
array([[ 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 1., 1., 1., 1., 1., 0.], 
     [ 0., 1., 1., 1., 1., 1., 0.], 
     [ 0., 1., 1., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0.]]) 

Oder wenn die Polsterung vor und nach dem identisch ist, aber unterschiedlich für die Achse, können Sie auch das zweite Argument weglassen in den inneren Tupeln:

>>> np.pad(a, [(1,), (2,)], mode='constant') 
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 1., 1., 1., 1., 1., 0., 0.], 
     [ 0., 0., 1., 1., 1., 1., 1., 0., 0.], 
     [ 0., 0., 1., 1., 1., 1., 1., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0.]]) 

aber ich bevorzuge immer dazu neigen, die explizit eine verwenden, weil es einfach zu leicht ist, Fehler zu machen (wenn NumPys Erwartungen von Ihren Absichten abweichen):

>>> np.pad(a, [1, 2], mode='constant') 
array([[ 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 1., 1., 1., 1., 1., 0., 0.], 
     [ 0., 1., 1., 1., 1., 1., 0., 0.], 
     [ 0., 1., 1., 1., 1., 1., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0.]]) 

Hier NumPy denkt, dass Sie alle Achsen mit 1 Element vor und 2 Elementen nach jeder Achse auffüllen möchten! Selbst wenn Sie es mit 1 Element in Achse 1 und 2 Elementen für Achse 2 auffüllen wollten.

Ich habe Listen von Tupeln für die Auffüllung verwendet, beachten Sie, dass dies nur "meine Konvention" ist, könnten Sie auch Listen verwenden oder Tupel-Tupel oder sogar Tupel von Arrays. NumPy prüft nur die Länge des Arguments (oder wenn es keine Länge hat) und die Länge jedes Elements (oder wenn es eine Länge hat)!

0

Im Fall benötigen Sie einen Zaun von 1s zu einem Array hinzuzufügen:

mat = np.zeros((4,4), np.int32) mat array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) mat[0,:] = mat[:,0] = mat[:,-1] = mat[-1,:] = 1 mat array([[1, 1, 1, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 1, 1]])

Danke.