python - ¿Buenas maneras de "expandir" un ndarray numpy?
numpy reshape (6)
¿Hay buenas maneras de "expandir" un ndarray numpy? Digamos que tengo una ndarray como esta:
[[1 2]
[3 4]]
Y quiero que cada fila contenga más elementos al completar ceros:
[[1 2 0 0 0]
[3 4 0 0 0]]
Sé que debe haber algunas formas de fuerza bruta para hacerlo (por ejemplo, construir una matriz más grande con ceros y luego copiar elementos de antiguas matrices más pequeñas), simplemente preguntándome si hay maneras pitónicas de hacerlo. Intentó numpy.reshape
pero no funcionó:
import numpy as np
a = np.array([[1, 2], [3, 4]])
np.reshape(a, (2, 5))
Numpy se queja de que: ValueError: total size of new array must be unchanged
Una manera simple:
# what you want to expand
x = np.ones((3, 3))
# expand to what shape
target = np.zeros((6, 6))
# do expand
target[:x.shape[0], :x.shape[1]] = x
# print target
array([[ 1., 1., 1., 0., 0., 0.],
[ 1., 1., 1., 0., 0., 0.],
[ 1., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.]])
Forma funcional:
tome prestado de https://.com/a/35751427/1637673 , con una pequeña modificación.
def pad(array, reference_shape, offsets=None):
"""
array: Array to be padded
reference_shape: tuple of size of narray 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
"""
if not offsets:
offsets = np.zeros(array.ndim, dtype=np.int32)
# Create an array of zeros with the reference shape
result = np.zeros(reference_shape, dtype=np.float32)
# 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
Debe usar np.column_stack
o append
import numpy as np
p = np.array([ [1,2] , [3,4] ])
p = np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )
p
Out[277]:
array([[1, 2, 0, 0],
[3, 4, 0, 0]])
Sin embargo, Anexar parece ser más rápido:
timeit np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )
10000 loops, best of 3: 61.8 us per loop
timeit np.append(p, [[0,0],[0,0]],1)
10000 loops, best of 3: 48 us per loop
Y una comparación con np.c_
y np.hstack
[append todavía parece ser el más rápido]:
In [295]: z=np.zeros((2, 2), dtype=a.dtype)
In [296]: timeit np.c_[a, z]
10000 loops, best of 3: 47.2 us per loop
In [297]: timeit np.append(p, z,1)
100000 loops, best of 3: 13.1 us per loop
In [305]: timeit np.hstack((p,z))
10000 loops, best of 3: 20.8 us per loop
y np.concatenate
[que es incluso un poco más rápido que append
]:
In [307]: timeit np.concatenate((p, z), axis=1)
100000 loops, best of 3: 11.6 us per loop
Existen los trucos de índice r_
y c_
.
>>> import numpy as np
>>> a = np.array([[1, 2], [3, 4]])
>>> z = np.zeros((2, 3), dtype=a.dtype)
>>> np.c_[a, z]
array([[1, 2, 0, 0, 0],
[3, 4, 0, 0, 0]])
Si se trata de un código de rendimiento crítico, es posible que prefiera utilizar el np.concatenate
equivalente en lugar de los trucos de índice.
>>> np.concatenate((a,z), axis=1)
array([[1, 2, 0, 0, 0],
[3, 4, 0, 0, 0]])
También hay np.resize
y np.ndarray.resize
, pero tienen algunas limitaciones (debido a la forma en que numpy establece los datos en la memoria) así que lee la docstring en esos. Probablemente descubrirá que simplemente concatenar es mejor.
Por cierto, cuando he necesitado hacer esto, generalmente lo hago de la manera básica que ya mencionaste (crear una matriz de ceros y asignar la matriz más pequeña dentro de él), ¡no veo nada de malo en eso!
Para que quede claro: no hay una "buena" forma de extender una matriz NumPy, ya que las matrices NumPy no son expandibles. Una vez que se define la matriz, el espacio que ocupa en la memoria, una combinación del número de sus elementos y el tamaño de cada elemento, se fija y no se puede cambiar. Lo único que puede hacer es crear una nueva matriz y reemplazar algunos de sus elementos por los elementos de la matriz original.
Hay muchas funciones disponibles para su comodidad (la función np.concatenate
y sus accesos directos de np.*stack
, np.column_stack
, las rutinas np.r_
y np.c_
...), pero solo hay eso: funciones de conveniencia . Algunos de ellos están optimizados en el nivel C (el np.concatenate
y otros, creo), otros no.
Tenga en cuenta que no hay nada en absoluto con su sugerencia inicial de crear una gran matriz ''a mano'' (posiblemente llena de ceros) y llenarla usted mismo con su matriz inicial. Puede ser más legible que las soluciones más complicadas.
Puedes usar numpy.pad
, de la siguiente manera:
>>> import numpy as np
>>> a=[[1,2],[3,4]]
>>> np.pad(a, ((0,0),(0,3)), mode=''constant'', constant_values=0)
array([[1, 2, 0, 0, 0],
[3, 4, 0, 0, 0]])
Aquí np.pad
dice: "Tome la matriz a
y agregue 0 filas encima de ella, 0 filas debajo de ella, 0 columnas a la izquierda y 3 columnas a la derecha de ésta. Llene estas columnas con una constant
especificada por constant_values
" .
también hay métodos similares como np.vstack, np.hstack, np.dstack. Me gustan estos sobre np.concatente, ya que deja en claro qué dimensión se está "expandiendo".
temp = np.array([[1, 2], [3, 4]])
np.hstack((temp, np.zeros((2,3))))
es fácil de recordar porque el primer eje de numpy es vertical, por lo que vstack expande el primer eje y el segundo eje es horizontal, por lo que hstack.