Indagamos en todo el mundo on line para así brindarte la solución para tu inquietud, si continúas con alguna pregunta déjanos un comentario y contestamos sin falta.
Solución:
NumPy 1.7.0 (cuando numpy.pad
se agregó) es bastante antiguo ahora (se lanzó en 2013), por lo que aunque la pregunta pedía una forma sin uso esa función pensé que podría ser útil saber cómo se podría lograr usando numpy.pad
.
En realidad, es bastante 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.]])
En este caso usé eso 0
es el valor predeterminado para mode='constant'
. Pero también podría especificarse pasándolo explícitamente:
>>> 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.]])
Por si acaso el segundo argumento ([(0, 1), (0, 1)]
) parece confuso: cada elemento de la lista (en este caso, tupla) corresponde a una dimensión y el elemento en el mismo representa el relleno antes de (primer elemento) y después (segundo elemento). Entonces:
[(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.
En este caso, el relleno para el primer y segundo eje es idéntico, por lo que también se podría pasar en la 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.]])
En caso de que el relleno antes y después sea idéntico, se podría incluso omitir la tupla (aunque no es aplicable en este 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.]])
O si el relleno antes y después es idéntico pero diferente para el eje, también puede omitir el segundo argumento en las 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.]])
Sin embargo, tiendo a preferir siempre usar el explícito, porque es demasiado fácil cometer errores (cuando las expectativas de NumPys difieren de sus intenciones):
>>> 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.]])
¡Aquí NumPy cree que querías rellenar todos los ejes con 1 elemento antes y 2 elementos después de cada eje! Incluso si tenía la intención de rellenar con 1 elemento en el eje 1 y 2 elementos para el eje 2.
Usé listas de tuplas para el relleno, tenga en cuenta que esto es solo “mi convención”, también podría usar listas de listas o tuplas de tuplas, o incluso tuplas de matrices. ¡NumPy solo verifica la longitud del argumento (o si no tiene una longitud) y la longitud de cada elemento (o si tiene una longitud)!
Muy simple, creas un array que contiene ceros usando la forma de referencia:
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
y luego inserte el array donde lo necesitas:
result[:a.shape[0],:a.shape[1]] = a
y listo lo has acolchado:
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.]])
También puede hacerlo un poco más general si define dónde debe insertarse el elemento superior izquierdo
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.]])
pero luego tenga cuidado de no tener compensaciones mayores que las permitidas. Para x_offset = 2
por ejemplo, esto fallará.
Si tiene un número arbitrario de dimensiones, puede definir una lista de cortes para insertar el original. array. Me pareció interesante jugar un poco y creé una función de relleno que puede rellenar (con compensación) una forma arbitraria array siempre y cuando el array y la referencia tienen el mismo número de dimensiones y las compensaciones no son demasiado 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
Y algunos casos de prueba:
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)
Entiendo que tu principal problema es que necesitas calcular d=b-a
pero sus matrices tienen diferentes tamaños. No es necesario un acolchado intermedio c
Puede resolver esto sin relleno:
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
Producción:
[[ 2. 2. 2. 2. 2. 3.]
[ 2. 2. 2. 2. 2. 3.]
[ 2. 2. 2. 2. 2. 3.]
[ 3. 3. 3. 3. 3. 3.]]
Reseñas y valoraciones
Recuerda dar difusión a este enunciado si te ayudó.