Wie kann ich aus einem Generatorobjekt ein Numpy-Array erstellen?
Lassen Sie mich das Problem veranschaulichen:
>>> 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])
In diesem Fall gimme()
handelt es sich um den Generator, dessen Ausgabe ich in ein Array verwandeln möchte. Der Array-Konstruktor iteriert jedoch nicht über den Generator, sondern speichert einfach den Generator selbst. Das Verhalten, das ich mir wünsche, ist das von numpy.array(list(gimme()))
, aber ich möchte nicht den Speicheraufwand dafür bezahlen, dass die Zwischenliste und das endgültige Array gleichzeitig im Speicher sind. Gibt es einen platzsparenderen Weg?
from numpy import *; print any(False for i in range(1))
- was das Eingebaute beschattetany()
und das gegenteilige Ergebnis erzeugt (wie ich jetzt weiß).numpy
Generatoren nicht wie Python behandelt werden können (oder wollen), sollte zumindest eine Ausnahme ausgelöst werden, wenn ein Generator als Argument empfangen wird.Antworten:
Bei Numpy-Arrays muss ihre Länge im Gegensatz zu Python-Listen zum Zeitpunkt der Erstellung explizit festgelegt werden. Dies ist erforderlich, damit Speicherplatz für jedes Element nacheinander im Speicher zugewiesen werden kann. Die fortlaufende Zuweisung ist das Hauptmerkmal von Numpy-Arrays: In Kombination mit der Implementierung von nativem Code können Operationen an ihnen viel schneller ausgeführt werden als reguläre Listen.
Vor diesem Hintergrund ist es technisch unmöglich, ein Generatorobjekt in ein Array umzuwandeln, es sei denn, Sie:
kann vorhersagen, wie viele Elemente es beim Ausführen ergeben wird:
sind bereit, ihre Elemente in einer Zwischenliste zu speichern:
Sie können zwei identische Generatoren erstellen, den ersten durchlaufen, um die Gesamtlänge zu ermitteln, das Array initialisieren und dann den Generator erneut durchlaufen, um jedes Element zu finden:
1 ist wahrscheinlich das, wonach Sie suchen. 2 ist platzsparend und 3 zeitlich ineffizient (Sie müssen den Generator zweimal durchlaufen).
quelle
array.array
ist eine zusammenhängende nicht verknüpfte Liste, und Sie können einfacharray.array('f', generator)
. Zu sagen, dass es unmöglich ist, ist irreführend. Es ist nur eine dynamische Zuordnung.Ein Google hinter diesem Stackoverflow-Ergebnis fand ich, dass es eine gibt
numpy.fromiter(data, dtype, count)
. Die Standardeinstellungcount=-1
übernimmt alle Elemente aus der Iterable. Es erfordert einedtype
explizite Einstellung. In meinem Fall hat das funktioniert:numpy.fromiter(something.generate(from_this_input), float)
quelle
numpy.fromiter(gimme(), float, count=-1)
funktioniert nicht. Wofür stehtsomething
?numpy.fromiter(gimme(), float, count=-1)
arbeitet für mich.fromiter
nur 1D-Arrays funktionieren : mail.scipy.org/pipermail/numpy-discussion/2007-August/… .count=-1
muss nicht angegeben werden, da dies die Standardeinstellung ist.count
an, um die Leistung zu verbessern. Auf diese Weise wird der Speicher zugewiesen, bevor er mit Werten gefüllt wird, anstatt bei Bedarf die Größe zu ändern (siehe Dokumentation vonnumpy.fromiter
)Während Sie ein 1D-Array aus einem Generator mit
numpy.fromiter()
erstellen können, können Sie ein ND-Array aus einem Generator erstellen mitnumpy.stack
:Es funktioniert auch für 1D-Arrays:
Beachten Sie, dass
numpy.stack
der Generator intern verbraucht und eine Zwischenliste mit erstellt wirdarrays = [asanyarray(arr) for arr in arrays]
. Die Implementierung finden Sie hier .quelle
np.array(tuple(mygen))
. Hier sind die Testergebnisse: im%timeit np.stack(permutations(range(10), 7)) 1 loop, best of 3: 1.9 s per loop
Vergleich zu%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.
Etwas tangential, aber wenn Ihr Generator ein Listenverständnis ist, können Sie es verwenden
numpy.where
, um Ihr Ergebnis effektiver zu erhalten (ich habe dies in meinem eigenen Code entdeckt, nachdem ich diesen Beitrag gesehen habe).quelle
Die Funktionen vstack , hstack und dstack können als Eingabegeneratoren verwendet werden, die mehrdimensionale Arrays ergeben.
quelle