Comment puis-je construire un tableau numpy à partir d'un générateur?
Comment puis-je construire un tableau numpy d'un générateur d'objet?
Permettez-moi d'illustrer le problème:
>>> import numpy
>>> def gimme():
... for x in xrange(10):
... yield x
...
>>> gimme()
<generator object at 0x28a1758>
>>> list(gimme())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> numpy.array(xrange(10))
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> numpy.array(gimme())
array(<generator object at 0x28a1758>, dtype=object)
>>> numpy.array(list(gimme()))
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Dans ce cas, donnez-moi de la() est le générateur dont la sortie j'aimerais tourner dans un tableau. Toutefois, la gamme du constructeur de ne pas effectuer une itération sur le générateur, il enregistre simplement le générateur lui-même. Le comportement que je désire, c'est que de numpy.tableau(liste(gimme())), mais je ne veux pas payer la surcharge de la mémoire d'avoir l'intermédiaire de la liste et le tableau final dans la mémoire en même temps. Est-il plus d'espace-efficace?
- C'est une question intéressante. Je suis tombé sur ce par
from numpy import *; print any(False for i in range(1))
- qui masque le haut-any()
et produit le résultat inverse (comme je le sais maintenant). - c'est terrible. si
numpy
ne peut pas (ou ne veut pas) pour traiter les générateurs de Python n'a, au moins, il devrait soulever une exception lorsqu'il reçoit un générateur comme argument. - J'ai exactement la même mine. Apparemment, cela a été soulevée sur le NumPy liste (et précédente) concluant que ce ne sera pas modifié pour lever exception et on devrait toujours utiliser des espaces de noms.
Vous devez vous connecter pour publier un commentaire.
Tableaux Numpy besoin de leur longueur à définir explicitement au moment de la création, contrairement à python listes. Ceci est nécessaire afin que l'espace pour chaque élément peut être consécutivement alloué dans la mémoire. Consécutives de répartition est l'élément clé de tableaux numpy: ceci, combiné avec du code natif de mise en œuvre de laisser opérations sur les exécuter beaucoup plus vite que les listes.
Gardant cela à l'esprit, il est techniquement impossible de prendre un générateur d'objet et de le transformer en un tableau, à moins que vous:
peut prédire combien d'éléments il donnera lors de l'exécution à:
sont prêts à stocker ses éléments dans une position intermédiaire de la liste :
peut faire deux générateurs identiques, courir à travers le premier à trouver la longueur totale, initialiser le tableau, puis exécutez à travers le générateur encore à trouver chaque élément:
1 est probablement ce que vous cherchez. 2 est l'espace inefficace, et 3 est à la fois inefficace (vous devez passer par le générateur à deux reprises).
array.array
est une ligne de non-lié liste, et vous pouvez simplementarray.array('f', generator)
. Dire que dire que c'est impossible, c'est trompeur. C'est juste de l'allocation dynamique.Google derrière cette stackoverflow résultat, j'ai trouvé qu'il y est un
numpy.fromiter(données, dtype, comte)
. La valeur par défautcount=-1
prend tous les éléments de l'itératif. Il nécessite undtype
être définies explicitement. Dans mon cas, cela a fonctionné:numpy.fromiter(something.generate(from_this_input), float)
numpy.fromiter(gimme(), float, count=-1)
ne fonctionne pas. Ce n'something
stand for?fromiter
ne fonctionne que sur les tableaux 1D: mail.scipy.org/pipermail/numpy-discussion/2007-August/....count=-1
n'a pas besoin d'être spécifié, comme c'est le défaut.numpy
ne pouvait pas/n'est pas défini par défautdtype=None
. S'ils le faisaient, il aurait la même interface quepd.array
. Ils pourraient en déduire dtype au sein de la fonction en récupérant le premier élément en dehors de la boucle iterattion, puis définissez le tableaudtype
à ce premier type de l'élément commedtype = dtype or type(iterable_first_element)
count
pour améliorer les performances. De cette façon, il alloue de la mémoire avant de le remplir avec les valeurs plutôt que de redimensionnement sur la demande (voir la documentation denumpy.fromiter
)Si vous pouvez créer un tableau 1D à partir d'un générateur avec
numpy.fromiter()
, vous pouvez créer un N-D tableau à partir d'un générateur avecnumpy.stack
:Il fonctionne également pour les tableaux 1D:
Noter que
numpy.stack
est à l'intérieur de consommer de l'alternateur et de la création d'un intermédiaire de la liste avecarrays = [asanyarray(arr) for arr in arrays]
. La mise en œuvre peut être trouvé ici.np.array(tuple(mygen))
. Voici les résultats du test:%timeit np.stack(permutations(range(10), 7)) 1 loop, best of 3: 1.9 s per loop
par rapport à%timeit np.array(tuple(permutations(range(10), 7))) 1 loop, best of 3: 427 ms per loop
FutureWarning: arrays to stack must be passed as a "sequence" type such as list or tuple. Support for non-sequence iterables such as generators is deprecated as of NumPy 1.16 and will raise an error in the future.
Un peu dans le sens tangentiel, mais si votre générateur est une compréhension de liste, vous pouvez utiliser
numpy.where
plus efficacement obtenir votre résultat (j'ai découvert cela dans mon propre code, après avoir vu ce post)La vstack, hstack, et dstack fonctions peuvent prendre en entrée des générateurs qui produisent des multi-dimensions des tableaux.