Bagaimana saya bisa membangun array numpy dari objek generator?
Biarkan saya menggambarkan masalahnya:
>>> 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])
Dalam contoh ini, gimme()
adalah generator yang outputnya ingin saya ubah menjadi sebuah array. Namun, konstruktor array tidak beralih di atas generator, ia hanya menyimpan generator itu sendiri. Perilaku yang saya inginkan adalah dari numpy.array(list(gimme()))
, tetapi saya tidak ingin membayar overhead memori memiliki daftar perantara dan array terakhir dalam memori pada saat yang sama. Apakah ada cara yang lebih efisien ruang?
from numpy import *; print any(False for i in range(1))
- yang membayangi built-inany()
dan menghasilkan hasil sebaliknya (seperti yang saya tahu sekarang).numpy
tidak bisa (atau tidak mau) untuk memperlakukan generator sebagai Python tidak, setidaknya harus menaikkan pengecualian ketika menerima generator sebagai argumen.Jawaban:
Array yang numpy membutuhkan panjangnya untuk diatur secara eksplisit pada waktu pembuatan, tidak seperti daftar python. Ini diperlukan agar ruang untuk setiap item dapat dialokasikan secara berurutan dalam memori. Alokasi berturut-turut adalah fitur utama array numpy: ini dikombinasikan dengan implementasi kode asli yang memungkinkan operasi pada mereka menjalankan jauh lebih cepat daripada daftar biasa.
Dengan mengingat hal ini, secara teknis tidak mungkin untuk mengambil objek generator dan mengubahnya menjadi sebuah array kecuali Anda:
dapat memprediksi berapa banyak elemen yang akan dihasilkan saat dijalankan:
bersedia menyimpan elemen-elemennya dalam daftar perantara:
dapat membuat dua generator identik, jalankan melalui yang pertama untuk menemukan total panjang, menginisialisasi array, dan kemudian jalankan melalui generator lagi untuk menemukan setiap elemen:
1 mungkin yang Anda cari. 2 tidak efisien ruang, dan 3 tidak efisien waktu (Anda harus melewati generator dua kali).
sumber
array.array
adalah daftar tidak terhubung yang berdekatan, dan Anda dapat melakukannya dengan mudaharray.array('f', generator)
. Mengatakan mengatakan itu tidak mungkin adalah menyesatkan. Itu hanya alokasi dinamis.Satu google di belakang hasil stackoverflow ini, saya menemukan bahwa ada
numpy.fromiter(data, dtype, count)
. Defaultcount=-1
mengambil semua elemen dari iterable. Ini membutuhkandtype
untuk diatur secara eksplisit. Dalam kasus saya, ini berhasil:numpy.fromiter(something.generate(from_this_input), float)
sumber
numpy.fromiter(gimme(), float, count=-1)
tidak bekerja. Apa artinyasomething
?numpy.fromiter(gimme(), float, count=-1)
bekerja untuk saya.fromiter
hanya berfungsi pada array 1D: mail.scipy.org/pipermail/numpy-discussion/2007-August/… .count=-1
tidak perlu ditentukan, karena ini adalah default.count
untuk meningkatkan kinerja. Dengan cara ini mengalokasikan memori sebelum mengisinya dengan nilai daripada mengubah ukuran sesuai permintaan (lihat dokumentasinumpy.fromiter
)Meskipun Anda bisa membuat array 1D dari generator dengan
numpy.fromiter()
, Anda bisa membuat array ND dari generator dengannumpy.stack
:Ini juga berfungsi untuk array 1D:
Catatan yang
numpy.stack
mengkonsumsi generator internal dan membuat daftar perantara denganarrays = [asanyarray(arr) for arr in arrays]
. Implementasinya dapat ditemukan di sini .sumber
np.array(tuple(mygen))
. Berikut adalah hasil tesnya:%timeit np.stack(permutations(range(10), 7)) 1 loop, best of 3: 1.9 s per loop
dibandingkan dengan%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.
Agak menyinggung, tetapi jika generator Anda adalah pemahaman daftar, Anda dapat menggunakan
numpy.where
untuk lebih efektif mendapatkan hasil Anda (saya menemukan ini dalam kode saya sendiri setelah melihat posting ini)sumber
Fungsi vstack , hstack , dan dstack dapat digunakan sebagai generator input yang menghasilkan array multi-dimensi.
sumber