Jak mogę zbudować tablicę numpy z obiektu generatora?
Pozwólcie, że zilustruję problem:
>>> 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])
W tym przypadku gimme()
jest to generator, którego wyjście chciałbym zamienić na tablicę. Jednak konstruktor tablicy nie wykonuje iteracji po generatorze, po prostu przechowuje sam generator. Zachowanie, którego pragnę, jest takie numpy.array(list(gimme()))
, ale nie chcę płacić narzutu pamięci związanego z posiadaniem listy pośredniej i ostatniej tablicy w pamięci w tym samym czasie. Czy istnieje sposób bardziej efektywny przestrzennie?
from numpy import *; print any(False for i in range(1))
- co zacienia wbudowaneany()
i daje odwrotny skutek (jak już wiem).numpy
nie może (lub nie chce) traktować generatorów tak, jak robi to Python, powinien przynajmniej zgłosić wyjątek, gdy otrzyma generator jako argument.Odpowiedzi:
Tablice Numpy wymagają jawnego ustawienia ich długości podczas tworzenia, w przeciwieństwie do list Pythona. Jest to konieczne, aby miejsce dla każdego elementu mogło być kolejno przydzielane w pamięci. Kolejna alokacja jest kluczową cechą tablic numpy: w połączeniu z implementacją kodu natywnego operacje na nich są wykonywane znacznie szybciej niż zwykłe listy.
Mając to na uwadze, technicznie niemożliwe jest pobranie obiektu generatora i przekształcenie go w tablicę, chyba że:
potrafi przewidzieć, ile elementów da po uruchomieniu:
chcą przechowywać swoje elementy na liście pośredniej:
może utworzyć dwa identyczne generatory, przejść przez pierwszy, aby znaleźć całkowitą długość, zainicjować tablicę, a następnie ponownie uruchomić generator, aby znaleźć każdy element:
1 jest prawdopodobnie tym, czego szukasz. 2 to nieefektywne miejsce, a 3 to nieefektywne czasowo (musisz dwukrotnie przejść przez generator).
źródło
array.array
lista jest ciągłą, niepołączoną listą i możesz po prostuarray.array('f', generator)
. Powiedzieć, że to niemożliwe, jest mylące. To tylko alokacja dynamiczna.Jedno z Google za tym wynikiem przepełnienia stosu okazało się, że istnieje plik
numpy.fromiter(data, dtype, count)
. Domyślniecount=-1
pobiera wszystkie elementy z iterowalnego. Wymagadtype
jawnego ustawienia. W moim przypadku zadziałało:numpy.fromiter(something.generate(from_this_input), float)
źródło
numpy.fromiter(gimme(), float, count=-1)
nie działa. Co to znaczysomething
?numpy.fromiter(gimme(), float, count=-1)
działa dla mnie.fromiter
działa tylko na tablicach 1D: mail.scipy.org/pipermail/numpy-discussion/2007-August/… .count=-1
nie trzeba określać, ponieważ jest to ustawienie domyślne.count
aby poprawić wydajność. W ten sposób alokuje pamięć przed wypełnieniem jej wartościami zamiast zmiany rozmiaru na żądanie (patrz dokumentacjanumpy.fromiter
)Chociaż możesz utworzyć tablicę 1D z generatora za pomocą
numpy.fromiter()
, możesz utworzyć tablicę ND z generatora za pomocąnumpy.stack
:Działa również w przypadku tablic 1D:
Zauważ, że
numpy.stack
wewnętrznie zużywa generator i tworzy listę pośrednią zarrays = [asanyarray(arr) for arr in arrays]
. Implementację można znaleźć tutaj .źródło
np.array(tuple(mygen))
. Oto wyniki testu: w%timeit np.stack(permutations(range(10), 7)) 1 loop, best of 3: 1.9 s per loop
porównaniu do%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.
Nieco styczne, ale jeśli twój generator jest listą, możesz użyć,
numpy.where
aby skuteczniej uzyskać wynik (odkryłem to we własnym kodzie po obejrzeniu tego postu)źródło
Funkcje vstack , hstack i dstack mogą służyć jako generatory danych wejściowych, które generują wielowymiarowe tablice.
źródło