¿Cómo convertir la lista de matrices numpy en una sola matriz numpy?

103

Supongamos que tengo;

LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])] # inner lists are numpy arrays

Trato de convertir;

array([[1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5])

Lo estoy resolviendo iterando en vstack en este momento, pero es realmente lento para LIST especialmente grande

¿Qué sugieres para la mejor manera eficiente?

erogol
fuente
5
LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])]esta no es la sintaxis correcta de Python. Por favor aclare.
Marcin

Respuestas:

131

En general, puede concatenar una secuencia completa de matrices a lo largo de cualquier eje:

numpy.concatenate( LIST, axis=0 )

pero usted no tiene que preocuparse por la forma y la dimensión de cada matriz en la lista (para una salida de 3x5 de 2 dimensiones, es necesario asegurarse de que todos ellos son de 2 dimensiones matrices n-por-5 ya). Si desea concatenar matrices unidimensionales como filas de una salida bidimensional, debe ampliar su dimensionalidad.

Como señala la respuesta de Jorge, también existe la función stack, introducida en numpy 1.10:

numpy.stack( LIST, axis=0 )

Esto toma el enfoque complementario: crea una nueva vista de cada matriz de entrada y agrega una dimensión adicional (en este caso, a la izquierda, por lo que cada nmatriz 1D -elemento se convierte en una matriz 1 por n2D) antes de concatenar. Solo funcionará si todas las matrices de entrada tienen la misma forma, incluso a lo largo del eje de concatenación.

vstack(o equivalentemente row_stack) es a menudo una solución más fácil de usar porque tomará una secuencia de matrices de 1 y / o 2 dimensiones y expandirá la dimensionalidad automáticamente donde sea necesario y solo cuando sea necesario, antes de concatenar la lista completa. Cuando se requiere una nueva dimensión, se agrega a la izquierda. Nuevamente, puede concatenar una lista completa a la vez sin necesidad de iterar:

numpy.vstack( LIST )

Este comportamiento flexible también se muestra en el atajo sintáctico numpy.r_[ array1, ...., arrayN ](observe los corchetes). Esto es bueno para concatenar algunas matrices con nombres explícitos, pero no es bueno para su situación porque esta sintaxis no aceptará una secuencia de matrices, como su LIST.

También hay una función column_stacky un atajo análogos c_[...], para el apilamiento horizontal (en columnas), así como una función casi análoga, hstackaunque por alguna razón esta última es menos flexible (es más estricta en cuanto a la dimensionalidad de las matrices de entrada e intenta concatenar Matrices 1-D de extremo a extremo en lugar de tratarlas como columnas).

Finalmente, en el caso específico de apilamiento vertical de matrices 1-D, lo siguiente también funciona:

numpy.array( LIST )

... porque las matrices se pueden construir a partir de una secuencia de otras matrices, agregando una nueva dimensión al principio.

jez
fuente
5
Creo que quería una matriz 2d como salida.
Beefster
7

A partir de la versión 1.10 de NumPy, tenemos la pila de métodos . Puede apilar matrices de cualquier dimensión (todas iguales):

# List of arrays.
L = [np.random.randn(5,4,2,5,1,2) for i in range(10)]

# Stack them using axis=0.
M = np.stack(L)
M.shape # == (10,5,4,2,5,1,2)
np.all(M == L) # == True

M = np.stack(L, axis=1)
M.shape # == (5,10,4,2,5,1,2)
np.all(M == L) # == False (Don't Panic)

# This are all true    
np.all(M[:,0,:] == L[0]) # == True
all(np.all(M[:,i,:] == L[i]) for i in range(10)) # == True

Disfrutar,

Jorge E. Cardona
fuente
1

¡Revisé algunos de los métodos para el rendimiento de la velocidad y descubrí que no hay diferencia! La única diferencia es que al usar algunos métodos, debe verificar cuidadosamente la dimensión.

Sincronización:

|------------|----------------|-------------------|
|            | shape (10000)  |  shape (1,10000)  |
|------------|----------------|-------------------|
| np.concat  |    0.18280     |      0.17960      |
|------------|----------------|-------------------|
|  np.stack  |    0.21501     |      0.16465      |
|------------|----------------|-------------------|
| np.vstack  |    0.21501     |      0.17181      |
|------------|----------------|-------------------|
|  np.array  |    0.21656     |      0.16833      |
|------------|----------------|-------------------|

Como puede ver, probé 2 experimentos: usando np.random.rand(10000)y np.random.rand(1, 10000) Y si usamos matrices 2d np.stacky np.arraycreamos una dimensión adicional, result.shape es (1,10000,10000) y (10000,1,10000), por lo que necesitan acciones adicionales para evitar esto .

Código:

from time import perf_counter
from tqdm import tqdm_notebook
import numpy as np
l = []
for i in tqdm_notebook(range(10000)):
    new_np = np.random.rand(10000)
    l.append(new_np)



start = perf_counter()
stack = np.stack(l, axis=0 )
print(f'np.stack: {perf_counter() - start:.5f}')

start = perf_counter()
vstack = np.vstack(l)
print(f'np.vstack: {perf_counter() - start:.5f}')

start = perf_counter()
wrap = np.array(l)
print(f'np.array: {perf_counter() - start:.5f}')

start = perf_counter()
l = [el.reshape(1,-1) for el in l]
conc = np.concatenate(l, axis=0 )
print(f'np.concatenate: {perf_counter() - start:.5f}')
Mikhail_Sam
fuente