204 votes

Comment 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 efficace?

242voto

dhill Points 997

Un google derrière ce résultat de stackoverflow, j'ai trouvé qu'il y a numpy.fromiter(data, dtype, count) . La valeur par défaut count=-1 prend tous les éléments de l'itérable. Cela nécessite un dtype à définir explicitement. Dans mon cas, cela a fonctionné:

numpy.fromiter(something.generate(from_this_input), float)

149voto

shsmurfy Points 732

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

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

(a) prévoir la façon dont de nombreux éléments, il donnera lors de l'exécuter:

my_array = numpy.zeros(predict_length())
for i, el in enumerate(gimme()): my_array[i] = el

(b) sont disposés pour stocker ses éléments dans une position intermédiaire de la liste :

my_array = numpy.array(list(gimme()))

(c) peut prendre 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:

length = sum(1 for el in gimme())
my_array = numpy.zeros(length)
for i, el in enumerate(gimme()): my_array[i] = el

(un) est probablement ce que vous cherchez. (b) est l'espace inefficace, et (c) est à la fois inefficace (vous devez passer par le générateur à deux reprises).

6voto

Benjamin Horstman Points 361

Un peu tangentielle, mais si votre générateur est une compréhension de liste, vous pouvez utiliser numpy.where pour obtenir plus efficacement votre résultat (je l’ai découvert dans mon propre code après avoir vu ce post)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X