Comment convertir une liste de tableaux numpy en un seul tableau numpy?

103

Supposons que j'ai;

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

J'essaye de me convertir;

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

Je résous le problème par itération sur vstack en ce moment, mais c'est vraiment lent pour les listes particulièrement volumineuses

Que proposez-vous pour la meilleure manière efficace?

érogol
la source
5
LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])]ce n'est pas la bonne syntaxe python. Précisez s'il vous plaît.
Marcin

Réponses:

131

En général, vous pouvez concaténer toute une séquence de tableaux le long de n'importe quel axe:

numpy.concatenate( LIST, axis=0 )

mais vous ne devez vous soucier de la forme et dimensionnalité de chaque tableau dans la liste (pour 2 dimensions sortie 3x5, vous devez vous assurer qu'ils sont tous les n-par-5 tableaux déjà 2 dimensions). Si vous souhaitez concaténer des tableaux à une dimension en tant que lignes d'une sortie à deux dimensions, vous devez étendre leur dimensionnalité.

Comme le souligne la réponse de Jorge, il y a aussi la fonction stack, introduite dans numpy 1.10:

numpy.stack( LIST, axis=0 )

Cela prend l'approche complémentaire: il crée une nouvelle vue de chaque tableau d'entrée et ajoute une dimension supplémentaire (dans ce cas, sur la gauche, chaque ntableau -element 1D devient un tableau 1 par n2D) avant la concaténation. Cela ne fonctionnera que si tous les tableaux d'entrée ont la même forme, même le long de l'axe de concaténation.

vstack(ou de manière équivalente row_stack) est souvent une solution plus facile à utiliser car elle prendra une séquence de tableaux à 1 et / ou 2 dimensions et étendra la dimensionnalité automatiquement si nécessaire et uniquement si nécessaire, avant de concaténer la liste entière. Lorsqu'une nouvelle dimension est requise, elle est ajoutée à gauche. Encore une fois, vous pouvez concaténer une liste entière à la fois sans avoir à itérer:

numpy.vstack( LIST )

Ce comportement flexible est également présenté par le raccourci syntaxique numpy.r_[ array1, ...., arrayN ](notez les crochets). C'est bon pour concaténer quelques tableaux nommés explicitement mais ce n'est pas bon pour votre situation car cette syntaxe n'acceptera pas une séquence de tableaux, comme la vôtre LIST.

Il existe également une fonction column_stacket un raccourci analogues c_[...], pour l'empilement horizontal (par colonne), ainsi qu'une fonction presque analogique hstack- bien que, pour une raison quelconque, cette dernière soit moins flexible (elle est plus stricte sur la dimensionnalité des tableaux d'entrée et tente de concaténer Tableaux 1-D de bout en bout au lieu de les traiter comme des colonnes).

Enfin, dans le cas spécifique de l'empilement vertical de tableaux 1-D, ce qui suit fonctionne également:

numpy.array( LIST )

... parce que les tableaux peuvent être construits à partir d'une séquence d'autres tableaux, ajoutant une nouvelle dimension au début.

jez
la source
5
Je pense qu'il voulait un tableau 2d comme sortie.
Beefster
7

À partir de la version 1.10 de NumPy, nous avons la pile de méthodes . Il peut empiler des tableaux de n'importe quelle dimension (tous égaux):

# 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

Prendre plaisir,

Jorge E. Cardona
la source
1

J'ai vérifié certaines des méthodes pour les performances de vitesse et je trouve qu'il n'y a pas de différence! La seule différence est qu'en utilisant certaines méthodes, vous devez vérifier soigneusement la dimension.

Horaire:

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

Comme vous pouvez le voir, j'ai essayé 2 expériences - en utilisant np.random.rand(10000)et np.random.rand(1, 10000) Et si nous utilisons des tableaux 2d que np.stacket np.arraycréons une dimension supplémentaire - result.shape est (1,10000,10000) et (10000,1,10000) donc ils ont besoin d'actions supplémentaires pour éviter cela .

Code:

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