Jak przekonwertować listę tablic numpy do jednej tablicy numpy?

109

Załóżmy, że mam;

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

Próbuję się nawrócić;

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

Rozwiązuję to teraz przez iterację na vstack, ale jest to bardzo powolne dla szczególnie dużej LISTY

Co sugerujesz, aby uzyskać najlepszy sposób?

erogol
źródło
5
LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])]to nie jest poprawna składnia Pythona. Proszę o wyjaśnienie.
Marcin

Odpowiedzi:

139

Ogólnie rzecz biorąc, można łączyć całą sekwencję tablic wzdłuż dowolnej osi:

numpy.concatenate( LIST, axis=0 )

ale nie trzeba się martwić o kształcie i wymiarowości każdej tablicy na liście (dla 2-wymiarowej wyjście 3x5, trzeba upewnić się, że wszyscy są 2-wymiarowe n-by-5 tablice już). Jeśli chcesz połączyć jednowymiarowe tablice jako wiersze dwuwymiarowego wyniku, musisz rozszerzyć ich wymiarowość.

Jak wskazuje odpowiedź Jorge, istnieje również funkcja stack, wprowadzona w numpy 1.10:

numpy.stack( LIST, axis=0 )

Przyjmuje to podejście komplementarne: tworzy nowy widok każdej tablicy wejściowej i dodaje dodatkowy wymiar (w tym przypadku po lewej stronie, więc każda n-elementowa tablica 1D staje się tablicą 1-na- n2D) przed połączeniem. Będzie działać tylko wtedy, gdy wszystkie tablice wejściowe mają ten sam kształt - nawet wzdłuż osi konkatenacji.

vstack(lub równoważnie row_stack) jest często łatwiejszym w użyciu rozwiązaniem, ponieważ wymaga sekwencji jedno- i / lub dwuwymiarowych tablic i automatycznie rozszerza wymiarowanie w razie potrzeby i tylko w razie potrzeby, przed połączeniem całej listy razem. Tam, gdzie wymagany jest nowy wymiar, jest on dodawany po lewej stronie. Ponownie możesz połączyć całą listę naraz bez konieczności iteracji:

numpy.vstack( LIST )

To elastyczne zachowanie jest również widoczne w skrócie składniowym numpy.r_[ array1, ...., arrayN ](zwróć uwagę na nawiasy kwadratowe). Jest to dobre do konkatenacji kilku jawnie nazwanych tablic, ale nie jest dobre w twojej sytuacji, ponieważ ta składnia nie akceptuje sekwencji tablic, takich jak twoja LIST.

Istnieje również analogiczna funkcja column_stacki skrót c_[...]do układania poziomego (kolumnowego), a także funkcja prawie analogowa - hstackchociaż z jakiegoś powodu ta ostatnia jest mniej elastyczna (jest bardziej rygorystyczna w kwestii wymiarowania tablic wejściowych i próbuje łączyć Tablice 1-w od końca do końca zamiast traktować je jako kolumny).

Wreszcie, w szczególnym przypadku pionowego układania w stos tablic 1-D, działa również:

numpy.array( LIST )

... ponieważ tablice można zbudować z sekwencji innych tablic, nadając początekowi nowy wymiar.

jez
źródło
5
Myślę, że chciał mieć tablicę 2d jako dane wyjściowe.
Beefster
8

Począwszy od wersji NumPy 1.10, mamy stos metod . Może układać w stosy tablice o dowolnym wymiarze (wszystkie równe):

# 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

Cieszyć się,

Jorge E. Cardona
źródło
1

Sprawdziłem niektóre metody szybkości działania i stwierdziłem, że nie ma różnicy! Jedyna różnica polega na tym, że przy użyciu niektórych metod należy dokładnie sprawdzić wymiar.

Wyczucie czasu:

|------------|----------------|-------------------|
|            | 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      |
|------------|----------------|-------------------|

Jak widać, wypróbowałem 2 eksperymenty - używając np.random.rand(10000)i np.random.rand(1, 10000) A jeśli użyjemy tablic 2d niż np.stacki np.arrayutworzymy dodatkowy wymiar - result.shape to (1,10000,10000) i (10000,1,10000), więc potrzebują dodatkowych działań, aby tego uniknąć .

Kod:

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
źródło