¿Qué tal la misma pregunta, pero está intentando entrelazar matrices? Es decir, ayb son tridimensionales y no necesariamente del mismo tamaño en la primera dimensión. Nota: Solo se debe intercalar la primera dimensión.
Geronimo
Respuestas:
144
Me gusta la respuesta de Josh. Solo quería agregar una solución más mundana, habitual y un poco más detallada. No sé cuál es más eficiente. Espero que tengan un rendimiento similar.
import numpy as np
a = np.array([1,3,5])
b = np.array([2,4,6])
c = np.empty((a.size + b.size,), dtype=a.dtype)
c[0::2] = a
c[1::2] = b
A menos que la velocidad sea realmente importante, me inclinaría por esto, ya que es mucho más comprensible, lo cual es importante si alguien va a volver a mirarlo.
John Salvatier
6
+1 Jugué con los tiempos y su código sorprendentemente parece ser 2-5 veces más rápido dependiendo de las entradas. Sigo considerando que la eficiencia de este tipo de operaciones no es intuitiva, por lo que siempre vale la pena usarla timeitpara probar si una operación en particular es un cuello de botella en su código. Por lo general, hay más de una forma de hacer las cosas en numpy, por lo que definitivamente hay fragmentos de código de perfil.
JoshAdel
@JoshAdel: Supongo que si .reshapecrea una copia adicional de la matriz, eso explicaría un impacto de rendimiento 2x. Sin embargo, no creo que siempre tenga una copia. Supongo que la diferencia de 5x es solo para arreglos pequeños.
Paul
mirando .flagsy probando .basemi solución, parece que la remodelación al formato 'F' crea una copia oculta de los datos vstacked, por lo que no es una vista simple como pensé que sería. Y extrañamente, el 5x es solo para matrices de tamaño intermedio por alguna razón.
JoshAdel
Otra ventaja de esta respuesta es que no se limita a matrices de la misma longitud. Podría tejer nartículos con n-1artículos.
EliadL
62
Pensé que valdría la pena comprobar el rendimiento de las soluciones. Y este es el resultado:
# Setupimport numpy as np
defPaul(a, b):
c = np.empty((a.size + b.size,), dtype=a.dtype)
c[0::2] = a
c[1::2] = b
return c
defJoshAdel(a, b):return np.vstack((a,b)).reshape((-1,),order='F')
defxioxox(a, b):return np.ravel(np.column_stack((a,b)))
defBenjamin(a, b):return np.vstack((a,b)).ravel([-1])
defandersonvom(a, b):return np.hstack( zip(a,b) )
defbhanukiran(a, b):return np.dstack((a,b)).flatten()
defTai(a, b):return np.insert(b, obj=range(a.shape[0]), values=a)
defWill(a, b):return np.ravel((a,b), order='F')
# Timing setup
timings = {Paul: [], JoshAdel: [], xioxox: [], Benjamin: [], andersonvom: [], bhanukiran: [], Tai: [], Will: []}
sizes = [2**i for i in range(1, 20, 2)]
# Timingfor size in sizes:
func_input1 = np.random.random(size=size)
func_input2 = np.random.random(size=size)
for func in timings:
res = %timeit -o func(func_input1, func_input2)
timings[func].append(res)
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(1)
ax = plt.subplot(111)
for func in timings:
ax.plot(sizes,
[time.best for time in timings[func]],
label=func.__name__) # you could also use "func.__name__" here instead
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel('size')
ax.set_ylabel('time [seconds]')
ax.grid(which='both')
ax.legend()
plt.tight_layout()
En caso de que tenga numba disponible, también puede usarlo para crear una función:
import numba as nb
@nb.njitdefnumba_interweave(arr1, arr2):
res = np.empty(arr1.size + arr2.size, dtype=arr1.dtype)
for idx, (item1, item2) in enumerate(zip(arr1, arr2)):
res[idx*2] = item1
res[idx*2+1] = item2
return res
Podría ser un poco más rápido que las otras alternativas:
Vaya, esto es tan ilegible :) Este es uno de los casos en los que si no escribe un comentario adecuado en el código, puede volver loco a alguien.
Ilya Kogan
9
Son solo dos comandos numpy comunes encadenados. No creo que sea tan ilegible, aunque un comentario nunca está de más.
JoshAdel
1
@JohnAdel, bueno, no lo es numpy.vstack((a,b)).interweave():)
Ilya Kogan
6
@Ilya: Hubiera llamado a la función .interleave()personalmente :)
JoshAdel
¿Qué hace reshape?
Danijel
23
Aquí hay una respuesta más simple que algunas de las anteriores.
import numpy as np
a = np.array([1,3,5])
b = np.array([2,4,6])
inter = np.ravel(np.column_stack((a,b)))
Después de esto intercontiene:
array([1, 2, 3, 4, 5, 6])
Esta respuesta también parece ser ligeramente más rápida:
In [4]: %timeit np.ravel(np.column_stack((a,b)))
100000 loops, best of 3: 6.31 µs per loop
In [8]: %timeit np.ravel(np.dstack((a,b)))
100000 loops, best of 3: 7.14 µs per loop
In [11]: %timeit np.vstack((a,b)).ravel([-1])
100000 loops, best of 3: 7.08 µs per loop
vstack seguro es una opción, pero una solución más sencilla para su caso podría ser la hstack
>>> a = array([1,3,5])
>>> b = array([2,4,6])
>>> hstack((a,b)) #remember it is a tuple of arrays that this function swallows in.>>> array([1, 3, 5, 2, 4, 6])
>>> sort(hstack((a,b)))
>>> array([1, 2, 3, 4, 5, 6])
y lo que es más importante, esto funciona para formas arbitrarias de ayb
También es posible que desee probar dstack
>>> a = array([1,3,5])
>>> b = array([2,4,6])
>>> dstack((a,b)).flatten()
>>> array([1, 2, 3, 4, 5, 6])
-1 a la primera respuesta porque la pregunta no tiene nada que ver con la clasificación. +1 a la segunda respuesta, que es la mejor que he visto hasta ahora. Es por eso que las soluciones múltiples deben publicarse como respuestas múltiples. Divídalo en varias respuestas.
endolito
1
Otro one-liner: np.vstack((a,b)).T.ravel()
Uno más:np.stack((a,b),1).ravel()
Necesitaba hacer esto pero con matrices multidimensionales a lo largo de cualquier eje. Aquí hay una función rápida de propósito general a tal efecto. Tiene la misma firma de llamada que np.concatenate, excepto que todas las matrices de entrada deben tener exactamente la misma forma.
import numpy as np
definterleave(arrays, axis=0, out=None):
shape = list(np.asanyarray(arrays[0]).shape)
if axis < 0:
axis += len(shape)
assert0 <= axis < len(shape), "'axis' is out of bounds"if out isnotNone:
out = out.reshape(shape[:axis+1] + [len(arrays)] + shape[axis+1:])
shape[axis] = -1return np.stack(arrays, axis=axis+1, out=out).reshape(shape)
Respuestas:
Me gusta la respuesta de Josh. Solo quería agregar una solución más mundana, habitual y un poco más detallada. No sé cuál es más eficiente. Espero que tengan un rendimiento similar.
import numpy as np a = np.array([1,3,5]) b = np.array([2,4,6]) c = np.empty((a.size + b.size,), dtype=a.dtype) c[0::2] = a c[1::2] = b
fuente
timeit
para probar si una operación en particular es un cuello de botella en su código. Por lo general, hay más de una forma de hacer las cosas en numpy, por lo que definitivamente hay fragmentos de código de perfil..reshape
crea una copia adicional de la matriz, eso explicaría un impacto de rendimiento 2x. Sin embargo, no creo que siempre tenga una copia. Supongo que la diferencia de 5x es solo para arreglos pequeños..flags
y probando.base
mi solución, parece que la remodelación al formato 'F' crea una copia oculta de los datos vstacked, por lo que no es una vista simple como pensé que sería. Y extrañamente, el 5x es solo para matrices de tamaño intermedio por alguna razón.n
artículos conn-1
artículos.Pensé que valdría la pena comprobar el rendimiento de las soluciones. Y este es el resultado:
Esto muestra claramente que la respuesta más votada y aceptada (la respuesta de Paul) es también la opción más rápida.
El código se tomó de las otras respuestas y de otra sesión de preguntas y respuestas :
# Setup import numpy as np def Paul(a, b): c = np.empty((a.size + b.size,), dtype=a.dtype) c[0::2] = a c[1::2] = b return c def JoshAdel(a, b): return np.vstack((a,b)).reshape((-1,),order='F') def xioxox(a, b): return np.ravel(np.column_stack((a,b))) def Benjamin(a, b): return np.vstack((a,b)).ravel([-1]) def andersonvom(a, b): return np.hstack( zip(a,b) ) def bhanukiran(a, b): return np.dstack((a,b)).flatten() def Tai(a, b): return np.insert(b, obj=range(a.shape[0]), values=a) def Will(a, b): return np.ravel((a,b), order='F') # Timing setup timings = {Paul: [], JoshAdel: [], xioxox: [], Benjamin: [], andersonvom: [], bhanukiran: [], Tai: [], Will: []} sizes = [2**i for i in range(1, 20, 2)] # Timing for size in sizes: func_input1 = np.random.random(size=size) func_input2 = np.random.random(size=size) for func in timings: res = %timeit -o func(func_input1, func_input2) timings[func].append(res) %matplotlib notebook import matplotlib.pyplot as plt import numpy as np fig = plt.figure(1) ax = plt.subplot(111) for func in timings: ax.plot(sizes, [time.best for time in timings[func]], label=func.__name__) # you could also use "func.__name__" here instead ax.set_xscale('log') ax.set_yscale('log') ax.set_xlabel('size') ax.set_ylabel('time [seconds]') ax.grid(which='both') ax.legend() plt.tight_layout()
En caso de que tenga numba disponible, también puede usarlo para crear una función:
import numba as nb @nb.njit def numba_interweave(arr1, arr2): res = np.empty(arr1.size + arr2.size, dtype=arr1.dtype) for idx, (item1, item2) in enumerate(zip(arr1, arr2)): res[idx*2] = item1 res[idx*2+1] = item2 return res
Podría ser un poco más rápido que las otras alternativas:
fuente
roundrobin()
las recetas de itertools.Aquí hay un resumen:
c = numpy.vstack((a,b)).reshape((-1,),order='F')
fuente
numpy.vstack((a,b)).interweave()
:).interleave()
personalmente :)reshape
?Aquí hay una respuesta más simple que algunas de las anteriores.
import numpy as np a = np.array([1,3,5]) b = np.array([2,4,6]) inter = np.ravel(np.column_stack((a,b)))
Después de esto
inter
contiene:array([1, 2, 3, 4, 5, 6])
Esta respuesta también parece ser ligeramente más rápida:
In [4]: %timeit np.ravel(np.column_stack((a,b))) 100000 loops, best of 3: 6.31 µs per loop In [8]: %timeit np.ravel(np.dstack((a,b))) 100000 loops, best of 3: 7.14 µs per loop In [11]: %timeit np.vstack((a,b)).ravel([-1]) 100000 loops, best of 3: 7.08 µs per loop
fuente
Esto intercalará / entrelazará las dos matrices y creo que es bastante legible:
a = np.array([1,3,5]) #=> array([1, 3, 5]) b = np.array([2,4,6]) #=> array([2, 4, 6]) c = np.hstack( zip(a,b) ) #=> array([1, 2, 3, 4, 5, 6])
fuente
zip
en unalist
advertencia para evitar la depreciaciónTal vez esto sea más legible que la solución de @ JoshAdel:
c = numpy.vstack((a,b)).ravel([-1])
fuente
ravel
'sorder
argumento a la documentación es uno deC
,F
,A
, oK
. Creo que realmente lo desea.ravel('F')
, para el pedido de FORTRAN (primera columna)Mejorando la respuesta de @ xioxox:
import numpy as np a = np.array([1,3,5]) b = np.array([2,4,6]) inter = np.ravel((a,b), order='F')
fuente
vstack
seguro es una opción, pero una solución más sencilla para su caso podría ser lahstack
>>> a = array([1,3,5]) >>> b = array([2,4,6]) >>> hstack((a,b)) #remember it is a tuple of arrays that this function swallows in. >>> array([1, 3, 5, 2, 4, 6]) >>> sort(hstack((a,b))) >>> array([1, 2, 3, 4, 5, 6])
y lo que es más importante, esto funciona para formas arbitrarias de
a
yb
También es posible que desee probar
dstack
>>> a = array([1,3,5]) >>> b = array([2,4,6]) >>> dstack((a,b)).flatten() >>> array([1, 2, 3, 4, 5, 6])
¡Tienes opciones ahora!
fuente
Otro one-liner:
np.vstack((a,b)).T.ravel()
Uno más:
np.stack((a,b),1).ravel()
fuente
También se puede intentar
np.insert
. (Solución migrada de matrices numpy de Interleave )import numpy as np a = np.array([1,3,5]) b = np.array([2,4,6]) np.insert(b, obj=range(a.shape[0]), values=a)
Consulte el
documentation
ytutorial
para obtener más información.fuente
Necesitaba hacer esto pero con matrices multidimensionales a lo largo de cualquier eje. Aquí hay una función rápida de propósito general a tal efecto. Tiene la misma firma de llamada que
np.concatenate
, excepto que todas las matrices de entrada deben tener exactamente la misma forma.import numpy as np def interleave(arrays, axis=0, out=None): shape = list(np.asanyarray(arrays[0]).shape) if axis < 0: axis += len(shape) assert 0 <= axis < len(shape), "'axis' is out of bounds" if out is not None: out = out.reshape(shape[:axis+1] + [len(arrays)] + shape[axis+1:]) shape[axis] = -1 return np.stack(arrays, axis=axis+1, out=out).reshape(shape)
fuente