Eu quero saber como posso preencher um array numpy 2D com zeros usando python 2.6.6 com numpy versão 1.5.0. Desculpa! Mas essas são minhas limitações. Portanto, não posso usar np.pad
. Por exemplo, desejo preencher a
com zeros de forma que sua forma corresponda b
. O motivo pelo qual quero fazer isso é:
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 consigo pensar em fazer isso é anexando, no entanto, parece muito feio. existe uma solução mais limpa possivelmente usando b.shape
?
Editar, obrigado à resposta de MSeiferts. Tive que limpar um pouco e foi isso que consegui:
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
O NumPy 1.7.0 (quando
numpy.pad
foi adicionado) é muito antigo (foi lançado em 2013), então, embora a pergunta fosse sobre uma maneira de não usar essa função, pensei que seria útil saber como isso poderia ser feito usandonumpy.pad
.Na verdade, é muito 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, usei esse
0
é o valor padrão paramode='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 do segundo argumento (
[(0, 1), (0, 1)]
) parecer confuso: Cada item da lista (neste caso tupla) corresponde a uma dimensão e o item nele representa o preenchimento antes (primeiro elemento) e depois (segundo elemento). Então:Neste caso, o preenchimento para o primeiro e o segundo eixos são idênticos, portanto, também é possível apenas passar a 2-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.]])
No caso de o preenchimento antes e depois ser 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 for 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, tendo a preferir sempre usar o explícito, porque é muito 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, NumPy pensa que você queria preencher todos os eixos com 1 elemento antes e 2 elementos depois de cada eixo! Mesmo que você pretenda preencher com 1 elemento no eixo 1 e 2 elementos no eixo 2.
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 mesmo tuplas de arrays. NumPy apenas verifica o comprimento do argumento (ou se não tem comprimento) e o comprimento de cada item (ou se tem comprimento)!
fonte
mode='constant'
é o padrão sensato, portanto, o preenchimento com zeros pode ser obtido sem a necessidade de qualquer palavra-chave opcional, levando a um código um pouco mais legível.Eu entendo que seu principal problema é que você precisa calcular,
d=b-a
mas seus arrays têm tamanhos diferentes. Não há necessidade de um preenchimento intermediárioc
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
Resultado:
[[ 2. 2. 2. 2. 2. 3.] [ 2. 2. 2. 2. 2. 3.] [ 2. 2. 2. 2. 2. 3.] [ 3. 3. 3. 3. 3. 3.]]
fonte
Caso você precise adicionar uma cerca de 1s a um array:
>>> 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]])
fonte
Eu sei que estou um pouco atrasado para isso, mas no caso de você querer executar preenchimento relativo (também conhecido como preenchimento de borda), veja como você pode implementá-lo. Observe que a primeira instância de atribuição resulta em preenchimento de zero, portanto, você pode usar isso para preenchimento de zero e preenchimento relativo (aqui é onde você copia os valores de borda da matriz original para a matriz preenchida).
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
Análise de complexidade:
A solução ideal para isso é o método pad numpy. Após calcular a média de 5 execuções, np.pad com preenchimento relativo só é
8%
melhor do que a função definida acima. Isso mostra que este é um método ideal para preenchimento relativo e zero-padding.#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%
fonte
O Tensorflow também implementou funções para redimensionar / preencher imagens tf.image.pad tf.pad .
padded_image = tf.image.pad_to_bounding_box(image, top_padding, left_padding, target_height, target_width) padded_image = tf.pad(image, paddings, "CONSTANT")
Essas funções funcionam como outros recursos de pipeline de entrada do tensorflow e funcionarão muito melhor para aplicativos de aprendizado de máquina.
fonte