Diberikan array NumPy A , apa cara tercepat / paling efisien untuk menerapkan fungsi yang sama , f , ke setiap sel?
Misalkan kita akan tetapkan untuk A (i, j) yang f (A (i, j)) .
Fungsi, f , tidak memiliki keluaran biner, sehingga operasi mask tidak akan membantu.
Apakah iterasi loop ganda yang "jelas" (melalui setiap sel) merupakan solusi yang optimal?
Jawaban:
Anda bisa melakukan vektorisasi fungsi dan kemudian menerapkannya langsung ke array Numpy setiap kali Anda membutuhkannya:
Mungkin lebih baik untuk menentukan tipe keluaran eksplisit secara langsung saat melakukan vektorisasi:
sumber
vectorize
deskripsi fungsi: Fungsi vectorize disediakan terutama untuk kenyamanan, bukan untuk performa. Implementasinya pada dasarnya adalah for loop. Jadi ini kemungkinan besar tidak akan mempercepat proses sama sekali.vectorize
menentukan jenis pengembalian. Itu telah menghasilkan bug.frompyfunc
sedikit lebih cepat, tetapi mengembalikan larik objek dtype. Keduanya memberi umpan skalar, bukan baris atau kolom.np.vectorize
menggunakan fungsi saya (yang menggunakan RK45) memberi saya kecepatan faktor ~ 20.Pertanyaan serupa adalah: Memetakan array NumPy di tempat . Jika Anda dapat menemukan ufunc untuk f () Anda, maka Anda harus menggunakan parameter out.
sumber
Jika Anda bekerja dengan angka dan
f(A(i,j)) = f(A(j,i))
, Anda bisa menggunakan scipy.spatial.distance.cdist yang mendefinisikan f sebagai jarak antaraA(i)
danA(j)
.sumber
Saya yakin saya telah menemukan solusi yang lebih baik. Ide untuk mengubah fungsi menjadi fungsi universal python (lihat dokumentasi ), yang dapat melakukan komputasi paralel di bawah tenda.
Seseorang dapat menulis sendiri disesuaikan
ufunc
dalam C, yang pasti lebih efisien, atau dengan memanggilnp.frompyfunc
, yang merupakan metode pabrik bawaan. Setelah pengujian, ini lebih efisien daripadanp.vectorize
:Saya juga telah menguji sampel yang lebih besar, dan peningkatannya proporsional. Untuk perbandingan kinerja metode lain, lihat posting ini
sumber
Ketika 2d-array (atau nd-array) adalah C- atau F-contiguous, maka tugas memetakan sebuah fungsi ke dalam array 2d secara praktis sama dengan tugas memetakan fungsi ke dalam array 1d - kita hanya harus melihatnya seperti itu, mis
np.ravel(A,'K')
. via .Solusi yang memungkinkan untuk 1d-array telah dibahas misalnya di sini .
Namun, ketika memori dari 2d-array tidak bersebelahan, maka situasinya sedikit lebih rumit, karena seseorang ingin menghindari kemungkinan cache miss jika sumbu ditangani dalam urutan yang salah.
Numpy sudah memiliki mesin untuk memproses sumbu dalam urutan terbaik. Salah satu kemungkinan untuk menggunakan mesin ini adalah
np.vectorize
. Namun, dokumentasi numpynp.vectorize
menyatakan bahwa itu "disediakan terutama untuk kenyamanan, bukan untuk kinerja" - fungsi python yang lambat tetap menjadi fungsi python yang lambat dengan seluruh overhead terkait! Masalah lainnya adalah konsumsi memori yang besar - lihat contoh SO-post ini .Ketika seseorang ingin memiliki kinerja fungsi-C tetapi menggunakan mesin numpy, solusi yang baik adalah menggunakan numba untuk pembuatan ufunc, misalnya:
Ini mudah berdetak
np.vectorize
tetapi juga ketika fungsi yang sama akan dilakukan sebagai perkalian / penambahan numpy-array, yaituLihat lampiran jawaban ini untuk kode pengukuran waktu:
Versi Numba (hijau) sekitar 100 kali lebih cepat daripada fungsi python (yaitu
np.vectorize
), yang tidak mengherankan. Tetapi juga sekitar 10 kali lebih cepat daripada fungsionalitas numpy, karena versi numbas tidak memerlukan array perantara dan karenanya menggunakan cache lebih efisien.Meskipun pendekatan ufunc numba adalah pertukaran yang baik antara kegunaan dan kinerja, itu masih bukan yang terbaik yang bisa kami lakukan. Namun tidak ada solusi terbaik atau pendekatan terbaik untuk tugas apa pun - orang harus memahami apa saja batasannya dan bagaimana hal itu dapat dikurangi.
Misalnya, untuk fungsi transendental (misalnya
exp
,sin
,cos
) Numba tidak memberikan keuntungan apa pun atas numpy ininp.exp
(tidak ada array sementara yang dibuat - sumber utama kecepatan-up). Namun, instalasi Anaconda saya menggunakan VML Intel untuk vektor yang lebih besar dari 8192 - tidak dapat melakukannya jika memori tidak berdekatan. Jadi mungkin lebih baik untuk menyalin elemen ke memori yang berdekatan agar dapat menggunakan VML Intel:Untuk keadilan perbandingan, saya telah mematikan paralelisasi VML (lihat kode di lampiran):
Seperti yang bisa dilihat, begitu VML dijalankan, overhead penyalinan lebih dari kompensasi. Namun begitu data menjadi terlalu besar untuk cache L3, keuntungannya minimal karena tugas sekali lagi terikat pada memori-bandwidth.
Di sisi lain, numba juga dapat menggunakan SVML Intel, seperti yang dijelaskan dalam posting ini :
dan menggunakan VML dengan hasil paralelisasi:
Versi numba memiliki overhead yang lebih sedikit, tetapi untuk beberapa ukuran VML mengalahkan SVML meskipun ada overhead penyalinan tambahan - yang tidak mengejutkan karena ufunc numba tidak diparalelkan.
Daftar:
A. perbandingan fungsi polinom:
B. perbandingan dari
exp
:sumber
Semua jawaban di atas sebanding dengan baik, tetapi jika Anda perlu menggunakan fungsi kustom untuk pemetaan, dan Anda punya
numpy.ndarray
, dan Anda perlu mempertahankan bentuk array.Saya telah membandingkan hanya dua, tetapi itu akan mempertahankan bentuk
ndarray
. Saya telah menggunakan array dengan 1 juta entri untuk perbandingan. Di sini saya menggunakan fungsi persegi. Saya menyajikan kasus umum untuk array dimensi n. Untuk dua dimensi buat sajaiter
2D.Keluaran
di sini Anda dapat dengan jelas melihat
numpy.fromiter
fungsi persegi pengguna, gunakan pilihan Anda. Jika fungsi Anda bergantung padai, j
itu adalah indeks array, iterasi pada ukuran array sepertifor ind in range(arr.size)
, gunakannumpy.unravel_index
untuk mendapatkani, j, ..
berdasarkan indeks 1D Anda dan bentuk array numpy.unravel_indexJawaban ini terinspirasi oleh jawaban saya atas pertanyaan lain di sini
sumber