2009-11-23 8 views
18
en colonne

En Python pur, vous pouvez pousser la colonne de matrices par colonne assez facilement:matrices croissance dans NumPy

data = [] 
for i in something: 
    newColumn = getColumnDataAsList(i) 
    data.append(newColumn) 

tableau de NumPy n'a pas la fonction append. La fonction hstack ne fonctionne pas sur zéro des tableaux de taille, donc le suivant ne fonctionnera pas:

data = numpy.array([]) 
for i in something: 
    newColumn = getColumnDataAsNumpyArray(i) 
    data = numpy.hstack((data, newColumn)) # ValueError: arrays must have same number of dimensions 

Alors, mes options sont soit pour enlever le initalization iside la boucle avec condition appropriée:

data = None 
for i in something: 
    newColumn = getColumnDataAsNumpyArray(i) 
    if data is None: 
     data = newColumn 
    else: 
     data = numpy.hstack((data, newColumn)) # works 

... ou d'utiliser une liste Python et convertir est plus tard tableau:

data = [] 
for i in something: 
    newColumn = getColumnDataAsNumpyArray(i) 
    data.append(newColumn) 
data = numpy.array(data) 

Les deux variantes semblent un peu difficile à être. Y a-t-il de meilleures solutions?

Répondre

18

NumPy réellement a une fonction append, qu'il semble peut faire ce que vous voulez, par exemple,

import numpy as NP 
my_data = NP.random.random_integers(0, 9, 9).reshape(3, 3) 
new_col = NP.array((5, 5, 5)).reshape(3, 1) 
res = NP.append(my_data, new_col, axis=1) 

votre deuxième extrait (hstack) ne fonctionnera que si vous ajoutez une ligne, par exemple,

my_data = NP.random.random_integers(0, 9, 16).reshape(4, 4) 
# the line to add--does not depend on array dimensions 
new_col = NP.zeros_like(my_data[:,-1]).reshape(-1, 1) 
res = NP.hstack((my_data, new_col)) 

hstack g Vient le même résultat que concatenate((my_data, new_col), axis=1), je ne suis pas sûr de la façon dont ils comparent les performances.


Bien que ce soit la réponse la plus directe à votre question, je dois mentionner que le bouclage par une source de données pour remplir une cible via append, tout simplement bien en python, n'est pas idiomatiques NumPy. Voici pourquoi:

l'initialisation d'un tableau numpy est relativement cher, et avec ce motif python classique, vous encourez que le coût, plus ou moins, à chaque itération de la boucle (chaque append à un tableau numpy est à peu près comme l'initialisation un nouveau tableau avec une taille différente).

Pour cette raison, le motif commun dans NumPy pour l'addition itérative de colonnes à un tableau 2D est d'initialiser un tableau cible vide une fois (ou pré-allouer un tableau 2D NumPy présentant toutes les colonnes vides) la successivement les colonnes vides remplir en réglant la désirée par colonne offset (index) - beaucoup plus facile de montrer que d'expliquer:

>>> # initialize your skeleton array using 'empty' for lowest-memory footprint 
>>> M = NP.empty(shape=(10, 5), dtype=float) 

>>> # create a small function to mimic step-wise populating this empty 2D array: 
>>> fnx = lambda v : NP.random.randint(0, 10, v) 

tableau numpy comme remplir dans l'OP, à l'exception de chaque itération juste Réinitialise les valeurs de M aux décalages de colonne successifs

>>> for index, itm in enumerate(range(5)):  
     M[:,index] = fnx(10) 

>>> M 
    array([[ 1., 7., 0., 8., 7.], 
     [ 9., 0., 6., 9., 4.], 
     [ 2., 3., 6., 3., 4.], 
     [ 3., 4., 1., 0., 5.], 
     [ 2., 3., 5., 3., 0.], 
     [ 4., 6., 5., 6., 2.], 
     [ 0., 6., 1., 6., 8.], 
     [ 3., 8., 0., 8., 0.], 
     [ 5., 2., 5., 0., 1.], 
     [ 0., 6., 5., 9., 1.]]) 

bien sûr si vous ne sait à l'avance ce que la taille de votre tableau doit être créer un juste beaucoup plus grand que vous avez besoin et couper les parties « inutilisées » lorsque vous avez fini peuplant

>>> M[:3,:3] 
    array([[ 9., 3., 1.], 
     [ 9., 6., 8.], 
     [ 9., 7., 5.]]) 
+0

Poste très utile pour un débutant numpy. Question rapide: est-il une raison pour laquelle vous utilisez 'pour l'indice, itm dans enumerate (plage (5)):' plutôt que, par exemple, 'pour x dans la plage (5):' voyant comme index et itm ont la même valeur et un seul est utilisé. –

+0

@ JohnBarça merci pour les commentaires. Vous avez peut-être raison de dire que les détails de mon extrait de code auraient dû être choisis avec plus de soin - dans mon exemple, la valeur de 'index' à chaque itération est en effet la même que celle de la variable loop. C'est un artefact cependant - les valeurs de ces deux variables ne sont probablement pas égales en pratique (par exemple, l'itérable est une liste contenant des valeurs à passer à une fonction qui crée les tableaux 1D qui sont ensuite 'insérés' dans le tableau cible). – doug

1

En règle générale, il est coûteux de continuer à réaffecter la matrice NumPy - votre troisième solution est donc la meilleure en termes de performances.

Cependant, je pense que hstack va faire ce que vous voulez - la queue est dans le message d'erreur,

ValueError: arrays must have same number of dimensions`

Je devine que newColumn a deux dimensions (plutôt qu'un vecteur 1D), de sorte que vous avez besoin de données pour avoir aussi deux dimensions ..., par exemple, data = np.array([[]]) - ou bien faire de newColumn un vecteur 1D (en général, si les choses sont 1D, il vaut mieux les garder 1D en NumPy, donc la diffusion, etc. fonctionne mieux). Dans ce cas, utilisez np.squeeze(newColumn) et hstack ou vstack devrait fonctionner avec votre définition originale des données.

4

Habituellement, vous ne continuez pas à redimensionner un tableau NumPy lorsque vous le créez. Qu'est-ce que vous n'aimez pas dans votre troisième solution? Si elle est une matrice/très grand tableau, il pourrait être utile de l'allocation du tableau avant de commencer à attribuer ses valeurs:

x = len(something) 
y = getColumnDataAsNumpyArray.someLengthProperty 

data = numpy.zeros((x,y)) 
for i in something: 
    data[i] = getColumnDataAsNumpyArray(i) 
3

Le hstack peut travailler sur des tableaux de taille nulle:

import numpy as np 

N = 5 
M = 15 

a = np.ndarray(shape = (N, 0)) 
for i in range(M): 
    b = np.random.rand(N, 1) 
    a = np.hstack((a, b))