with python como pad numpy array com zeros




sum numpy python (4)

Eu quero saber como eu posso preencher um array numpy 2D com zeros usando o python 2.6.6 com a versão 1.5.0 numpy. Desculpa! Mas estas são minhas limitações. Portanto, não posso usar o np.pad . Por exemplo, eu quero preencher a com zeros de forma que sua forma coincida com b . A razão pela qual eu quero fazer isso é para que eu possa fazer:

b-a

de tal modo 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]])

A única maneira que posso pensar em fazer isso é acrescentar, no entanto, isso parece muito feio. Existe uma solução mais limpa, possivelmente usando b.shape ?

Edit, obrigado a MSeiferts responder. Eu tive que limpar um pouco, e é isso que eu recebi:

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

Eu entendo que o seu principal problema é que você precisa calcular d=ba mas suas matrizes têm tamanhos diferentes. Não há necessidade de um c acolchoado intermediário

Você pode resolver isso sem preenchimento:

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

Saída:

[[ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 3.  3.  3.  3.  3.  3.]]

Muito simples, você cria uma matriz contendo zeros usando a forma de referência:

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

e insira o array onde você precisa:

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

e voila você tem acolchoado:

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

Você também pode torná-lo um pouco mais geral se você definir onde seu elemento superior esquerdo deve ser inserido

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

mas tenha cuidado para não ter compensações maiores do que o permitido. Para x_offset = 2 por exemplo, isso falhará.

Se você tiver um número arbitrário de dimensões, poderá definir uma lista de fatias para inserir o array original. Achei interessante brincar um pouco e criei uma função de preenchimento que pode preencher (com deslocamento) uma matriz de formato arbitrário, desde que a matriz e a referência tenham o mesmo número de dimensões e as compensações não sejam muito grandes.

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

E alguns casos de teste:

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)

Caso você precise adicionar uma cerca de 1s a uma matriz:

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

O NumPy 1.7.0 (quando o numpy.pad foi adicionado) é bem antigo agora (foi lançado em 2013), então mesmo que a pergunta tenha sido feita sem usar essa função, achei que seria útil saber como isso poderia ser feito usando numpy.pad .

Na verdade é bem simples:

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

Neste caso eu usei que 0 é o valor padrão para mode='constant' . Mas também pode ser especificado passando-o explicitamente:

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

Apenas no caso de o segundo argumento ( [(0, 1), (0, 1)] ) parecer confuso: Cada item da lista (neste caso tupla) corresponde a uma dimensão e o item ali representa o preenchimento antes (primeiro elemento) e depois (segundo elemento). Assim:

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

Nesse caso, o preenchimento do primeiro e do segundo eixo é idêntico, de modo que também é possível passar a segunda tupla:

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

Caso o preenchimento antes e depois seja idêntico, pode-se até omitir a tupla (não aplicável neste caso):

>>> 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 se o preenchimento antes e depois é idêntico, mas diferente para o eixo, você também pode omitir o segundo argumento nas tuplas internas:

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

No entanto, eu costumo preferir usar sempre o explícito, porque é fácil cometer erros (quando as expectativas do NumPys diferem das suas intenções):

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

Aqui, o NumPy acha que você queria preencher todos os eixos com 1 elemento antes e 2 elementos depois de cada eixo! Mesmo se você pretendia que ele fosse preenchido com 1 elemento no eixo 1 e 2 elementos no eixo 2.

Eu usei listas de tuplas para o preenchimento, note que isso é apenas "minha convenção", você também pode usar listas de listas ou tuplas de tuplas, ou até mesmo tuplas de matrizes. NumPy apenas verifica o tamanho do argumento (ou se não tem comprimento) e o tamanho de cada item (ou se tem comprimento)!





pad