Ich möchte wissen, wie ich mit Python 2.6.6 mit Numpy Version 1.5.0 ein 2D-Numpy-Array mit Nullen auffüllen kann. Es tut uns leid! Aber das sind meine Grenzen. Daher kann ich nicht verwenden np.pad
. Zum Beispiel möchte ich a
mit Nullen auffüllen, damit die Form übereinstimmt b
. Der Grund, warum ich das tun möchte, ist, dass ich Folgendes tun kann:
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]])
Der einzige Weg, den ich mir vorstellen kann, ist das Anhängen, aber das scheint ziemlich hässlich. Gibt es möglicherweise eine sauberere Lösung b.shape
?
Bearbeiten, danke an MSeiferts Antwort. Ich musste es ein bisschen aufräumen, und das habe ich bekommen:
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
padded = np.zeros(b.shape)
padded[tuple(slice(0,n) for n in a.shape)] = a
NumPy 1.7.0 (als
numpy.pad
es hinzugefügt wurde) ist jetzt ziemlich alt (es wurde 2013 veröffentlicht). Obwohl die Frage nach einem Weg ohne diese Funktion gestellt wurde, hielt ich es für nützlich zu wissen, wie dies mit erreicht werden kannnumpy.pad
.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 verwendet, dass dies
0
der Standardwert für istmode='constant'
. Es kann aber auch durch explizite Übergabe 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, dass das zweite Argument (
[(0, 1), (0, 1)]
) verwirrend erscheint: Jedes Listenelement (in diesem Fall Tupel) entspricht einer Dimension, und das darin enthaltene Element repräsentiert die Auffüllung vor (erstes Element) und nach (zweites Element). Damit:In diesem Fall ist die Polsterung für die erste und zweite Achse identisch, so dass man auch einfach das 2-Tupel übergeben 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 Auffüllung vorher und nachher identisch ist, kann man sogar das Tupel weglassen (in diesem Fall jedoch nicht zutreffend):
>>> 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 Auffüllung vorher und nachher identisch, aber für die Achse unterschiedlich ist, können Sie auch das zweite Argument in den inneren Tupeln weglassen:
>>> 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.]])
Ich bevorzuge es jedoch, immer die explizite zu verwenden, da es einfach zu einfach ist, Fehler zu machen (wenn die Erwartungen von NumPys 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 glaubt NumPy, Sie wollten alle Achsen mit 1 Element vor und 2 Elementen nach jeder Achse auffüllen! Auch wenn Sie beabsichtigten, mit 1 Element in Achse 1 und 2 Elementen für Achse 2 aufzufüllen.
Ich habe Listen mit Tupeln für das Auffüllen verwendet. Beachten Sie, dass dies nur "meine Konvention" ist. Sie können auch Listen mit Listen oder Tupeln mit Tupeln oder sogar Tupel mit Arrays verwenden. NumPy überprü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)!
quelle
mode='constant'
ist die sinnvolle Standardeinstellung, sodass das Auffüllen mit Nullen ohne ein optionales Schlüsselwort erreicht werden kann, was zu etwas besser lesbarem Code führt.Ich verstehe, dass Ihr Hauptproblem darin besteht, dass Sie berechnen müssen,
d=b-a
aber Ihre Arrays unterschiedliche Größen haben. Es ist kein gepolstertes Zwischenprodukt erforderlichc
Sie können dies ohne Polsterung lösen:
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
Ausgabe:
[[ 2. 2. 2. 2. 2. 3.] [ 2. 2. 2. 2. 2. 3.] [ 2. 2. 2. 2. 2. 3.] [ 3. 3. 3. 3. 3. 3.]]
quelle
Falls Sie einem Array einen Zaun von 1s hinzufügen müssen:
>>> 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]])
quelle
Ich weiß, dass ich etwas spät dran bin, aber falls Sie eine relative Auffüllung (auch als Kantenauffüllung bezeichnet) durchführen möchten, können Sie dies wie folgt implementieren. Beachten Sie, dass die allererste Instanz der Zuweisung zu einem Null-Auffüllen führt. Sie können dies also sowohl für das Null-Auffüllen als auch für das relative Auffüllen verwenden (hier kopieren Sie die Kantenwerte des ursprünglichen Arrays in das aufgefüllte Array).
def replicate_padding(arr): """Perform replicate padding on a numpy array.""" new_pad_shape = tuple(np.array(arr.shape) + 2) # 2 indicates the width + height to change, a (512, 512) image --> (514, 514) padded image. padded_array = np.zeros(new_pad_shape) #create an array of zeros with new dimensions # perform replication padded_array[1:-1,1:-1] = arr # result will be zero-pad padded_array[0,1:-1] = arr[0] # perform edge pad for top row padded_array[-1, 1:-1] = arr[-1] # edge pad for bottom row padded_array.T[0, 1:-1] = arr.T[0] # edge pad for first column padded_array.T[-1, 1:-1] = arr.T[-1] # edge pad for last column #at this point, all values except for the 4 corners should have been replicated padded_array[0][0] = arr[0][0] # top left corner padded_array[-1][0] = arr[-1][0] # bottom left corner padded_array[0][-1] = arr[0][-1] # top right corner padded_array[-1][-1] = arr[-1][-1] # bottom right corner return padded_array
Komplexitätsanalyse:
Die optimale Lösung hierfür ist die Numpy-Pad-Methode. Nach der Mittelung für 5 Läufe ist np.pad mit relativer Auffüllung nur
8%
besser als die oben definierte Funktion. Dies zeigt, dass dies eine ziemlich optimale Methode für relative und Null-Polsterung ist.#My method, replicate_padding start = time.time() padded = replicate_padding(input_image) end = time.time() delta0 = end - start #np.pad with edge padding start = time.time() padded = np.pad(input_image, 1, mode='edge') end = time.time() delta = end - start print(delta0) # np Output: 0.0008790493011474609 print(delta) # My Output: 0.0008130073547363281 print(100*((delta0-delta)/delta)) # Percent difference: 8.12316715542522%
quelle