Jak zbudować tablicę numpy z generatora?

Jak mogę zbudować tablicę numpy z obiektu generatora?

Pozwól mi zilustrować 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 generatorem, którego wyjście chciałbym przekształcić w tablicę. Jednak konstruktor tablicy nie iteruje nad generatorem, tylko przechowuje sam generator. Zachowanie, którego pragnę, jest takie, że z numpy.array(list(gimme())), ale nie chcę płacić narzutu pamięci z posiadania listy pośredniej i końcowej tablicy w pamięci w tym samym czas. Czy istnieje bardziej oszczędny sposób?

Author: Neuron, 2008-12-15

5 answers

Tablice Numpy wymagają, aby ich długość była ustawiana jawnie podczas tworzenia, w przeciwieństwie do list Pythona. Jest to konieczne, aby przestrzeń dla każdego elementu mogła być kolejno przydzielana w pamięci. Sekwencyjna alokacja jest kluczową cechą tablic numpy: w połączeniu z implementacją kodu natywnego operacje na nich wykonywane są znacznie szybciej niż zwykłe listy.

Mając to na uwadze, technicznie niemożliwe jest wzięcie obiektu generatora i przekształcenie go w tablicę, chyba że albo:

  1. Potrafi przewidzieć ile elementów wyda się po uruchomieniu:

    my_array = numpy.empty(predict_length())
    for i, el in enumerate(gimme()): my_array[i] = el
    
  2. Są chętni do przechowywania jego elementów na liście pośredniej:

    my_array = numpy.array(list(gimme()))
    
  3. Może utworzyć dwa identyczne Generatory, uruchomić pierwszy, aby znaleźć całkowitą długość, zainicjalizować tablicę, a następnie ponownie uruchomić generator, aby znaleźć każdy element:

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

1 pewnie tego szukasz. 2 jest przestrzeń nieefektywna, a 3 jest czas nieefektywny(trzeba przejść przez generator dwa razy).

 139
Author: shsmurfy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 13:31:01

Jeden google za tym wynikiem stackoverflow, stwierdziłem, że jest numpy.fromiter(data, dtype, count). Domyślna count=-1 pobiera wszystkie elementy z iterable. Wymaga jawnego Ustawienia dtype. W moim przypadku to zadziałało:

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

 218
Author: dhill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-21 21:09:08

Podczas gdy możesz utworzyć tablicę 1D z generatora za pomocą numpy.fromiter(), możesz utworzyć tablicę N-D z generatora za pomocą numpy.stack:

>>> mygen = (np.ones((5, 3)) for _ in range(10))
>>> x = numpy.stack(mygen)
>>> x.shape
(10, 5, 3)

Działa również dla tablic 1D:

>>> numpy.stack(2*i for i in range(10))
array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])

Zauważ, że {[3] } wewnętrznie zużywa generator i tworzy listę pośrednią z arrays = [asanyarray(arr) for arr in arrays]. Implementację można znaleźć tutaj .

[WARNING] Jak zauważył @Joseh Seedy, Numpy 1.16 wyświetla ostrzeżenie, które pokonuje użycie takiej funkcji z generatorami.

 17
Author: mdeff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-07 02:50:36

Nieco styczny, ale jeśli twój generator jest rozumieniem listy, możesz użyć numpy.where, aby skuteczniej uzyskać wynik (odkryłem to we własnym kodzie po obejrzeniu tego postu)

 6
Author: Benjamin Horstman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-05 18:38:55

The vstack, Funkcje hstack i dstack mogą przyjmować jako generatory wejściowe generujące wielowymiarowe tablice.

 0
Author: Mike R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-14 20:27:17