web-dev-qa-db-fra.com

python comment remplir un tableau numpy avec des zéros

Je souhaite savoir comment remplir un tableau 2D numpy avec des zéros à l'aide de python 2.6.6 avec Numpy version 1.5.0. Pardon! Mais ce sont mes limites. Par conséquent, je ne peux pas utiliser np.pad. Par exemple, je souhaite compléter a avec des zéros de sorte que sa forme corresponde à b. La raison pour laquelle je veux faire cela est pour que je puisse faire:

b-a

tel que

>>> 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]])

La seule façon dont je peux penser à faire cela est d’ajouter, mais cela semble plutôt moche. existe-t-il une solution plus propre utilisant éventuellement b.shape?

Modifier, merci à MSeiferts pour la réponse. J'ai du nettoyer un peu, et voici ce que j'ai eu:

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
52
user2015487

Très simple, vous créez un tableau contenant des zéros en utilisant la forme de référence:

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

puis insérez le tableau où vous en avez besoin:

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

et voila vous l'avez rembourré:

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.]])

Vous pouvez également le rendre un peu plus général si vous définissez où votre élément supérieur gauche doit être inséré

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.]])

mais alors veillez à ce que vos compensations ne soient pas supérieures à celles autorisées. Pour x_offset = 2 par exemple, cela échouera.


Si vous avez un nombre arbitraire de dimensions, vous pouvez définir une liste de tranches pour insérer le tableau d'origine. J'ai trouvé intéressant de jouer un peu et de créer une fonction de remplissage qui peut remplir (avec offset) un tableau de forme arbitraire, à condition que le tableau et la référence aient le même nombre de dimensions et que les décalages ne soient pas trop grands.

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

Et quelques cas de test:

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)
95
MSeifert

NumPy 1.7.0 (quand numpy.pad a été ajouté) est assez ancien à présent (sorti en 2013), alors que la question demandait un moyen sans utiliser cette fonction, j’ai pensé qu’il pourrait être utile de savoir comment y parvenir en utilisant numpy.pad .

C'est en fait assez simple:

_>>> 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.]])
_

Dans ce cas, j'ai utilisé que _0_ est la valeur par défaut pour _mode='constant'_. Mais on pourrait aussi le spécifier en le passant explicitement:

_>>> 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.]])
_

Juste au cas où le deuxième argument ([(0, 1), (0, 1)]) semble déroutant: chaque élément de la liste (dans ce cas Tuple) correspond à une dimension et l’item représente le remplissage avant (premier élément) et après (deuxième élément). Alors:

_[(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.
_

Dans ce cas, les marges des premier et deuxième axes sont identiques, on pourrait donc simplement passer dans le 2-Tuple:

_>>> 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.]])
_

Dans le cas où le remplissage avant et après est identique, vous pouvez même omettre le tuple (non applicable dans ce cas cependant):

_>>> 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.]])
_

Ou si le remplissage avant et après est identique mais différent pour l'axe, vous pouvez également omettre le deuxième argument dans les tuples internes:

_>>> 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.]])
_

Cependant, j'ai tendance à préférer toujours utiliser l'explicite, car il est trop facile de faire des erreurs (lorsque les attentes de NumPys diffèrent de vos intentions):

_>>> 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.]])
_

Ici, NumPy pense que vous vouliez remplir tous les axes avec 1 élément avant et 2 éléments après chaque axe! Même si vous vouliez le placer avec 1 élément dans l’axe 1 et 2 éléments dans l’axe 2.

J'ai utilisé des listes de n-uplets pour le remplissage, notez que ceci est juste "ma convention", vous pouvez également utiliser des listes de listes ou n-uplets de n-uplets, ou même de n-uplets de tableaux. NumPy vérifie simplement la longueur de l'argument (ou si elle n'a pas de longueur) et la longueur de chaque élément (ou si elle a une longueur)!

91
MSeifert

Je comprends que votre principal problème est que vous devez calculer d=b-a, mais vos tableaux ont des tailles différentes. Il n'y a pas besoin de rembourrage intermédiaire c

Vous pouvez résoudre ceci sans rembourrage:

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

Sortie:

[[ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 3.  3.  3.  3.  3.  3.]]
6
Juan Leni

Si vous devez ajouter une clôture de 1 à un tableau:

>>> 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]])
0
user3409057