Como converter a lista de matrizes numpy em matriz numpy única?

100

Suponha que sim;

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

Tento me converter;

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

Estou resolvendo isso por iteração no vstack agora, mas é muito lento para LIST especialmente grande

O que você sugere da maneira mais eficiente?

erogol
fonte
5
LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])]esta não é a sintaxe correta do Python. Por favor, esclareça.
Marcin

Respostas:

128

Em geral, você pode concatenar uma sequência inteira de matrizes ao longo de qualquer eixo:

numpy.concatenate( LIST, axis=0 )

mas você faz precisa se preocupar com a forma e dimensionalidade de cada matriz na lista (para uma saída de 3x5 2-dimensional, você precisa se certificar de que eles são todos os 2-dimensionais arrays de n-por-5 já). Se você deseja concatenar matrizes unidimensionais como as linhas de uma saída bidimensional, é necessário expandir sua dimensionalidade.

Como aponta a resposta de Jorge, há também a função stack, introduzida no numpy 1.10:

numpy.stack( LIST, axis=0 )

Isso leva a uma abordagem complementar: ele cria uma nova visualização de cada array de entrada e adiciona uma dimensão extra (neste caso, à esquerda, de modo que cada narray 1D -element torna-se um array 1 por n2D) antes de concatenar. Ele só funcionará se todas as matrizes de entrada tiverem a mesma forma - mesmo ao longo do eixo de concatenação.

vstack(ou de forma equivalente row_stack) é muitas vezes uma solução mais fácil de usar porque levará uma sequência de matrizes unidimensionais e / ou bidimensionais e expandirá a dimensionalidade automaticamente quando necessário e somente quando necessário, antes de concatenar a lista inteira. Onde uma nova dimensão é necessária, ela é adicionada à esquerda. Novamente, você pode concatenar uma lista inteira de uma vez, sem precisar iterar:

numpy.vstack( LIST )

Esse comportamento flexível também é exibido pelo atalho sintático numpy.r_[ array1, ...., arrayN ](observe os colchetes). Isso é bom para concatenar alguns arrays nomeados explicitamente, mas não é bom para sua situação porque essa sintaxe não aceita uma sequência de arrays, como o seu LIST.

Há também uma função column_stacke atalho análogos c_[...]para empilhamento horizontal (coluna), bem como uma função quase análogahstack - embora por algum motivo a última seja menos flexível (é mais estrita sobre a dimensionalidade dos arrays de entrada e tenta concatenar Arrays 1-D ponta a ponta em vez de tratá-los como colunas).

Finalmente, no caso específico de empilhamento vertical de matrizes 1-D, o seguinte também funciona:

numpy.array( LIST )

... porque os arrays podem ser construídos a partir de uma sequência de outros arrays, adicionando uma nova dimensão ao início.

Jez
fonte
5
Acho que ele queria uma matriz 2d como saída.
Beefster
7

A partir da versão 1.10 do NumPy, temos a pilha de métodos . Ele pode empilhar matrizes de qualquer dimensão (todas iguais):

# 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

Aproveitar,

Jorge E. Cardona
fonte
1

Eu verifiquei alguns dos métodos de desempenho de velocidade e descobri que não há diferença! A única diferença é que, usando alguns métodos, você deve verificar cuidadosamente as dimensões.

Cronometragem:

|------------|----------------|-------------------|
|            | 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 você pode ver, tentei 2 experimentos - usando np.random.rand(10000)e np.random.rand(1, 10000) E se usarmos matrizes 2d np.stacke np.arraycriarmos uma dimensão adicional - result.shape é (1,10000,10000) e (10000,1,10000) então eles precisam de ações adicionais para evitar isso .

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
fonte