Bagaimana saya bisa menemukan indeks kemunculan pertama angka dalam array Numpy? Kecepatan penting bagi saya. Saya tidak tertarik dengan jawaban berikut karena mereka memindai seluruh larik dan tidak berhenti ketika mereka menemukan kejadian pertama:
itemindex = numpy.where(array==item)[0][0]
nonzero(array == item)[0][0]
Catatan 1: tidak ada jawaban dari pertanyaan itu yang tampak relevan Apakah ada fungsi Numpy untuk mengembalikan indeks pertama dari sesuatu dalam sebuah array?
Catatan 2: menggunakan metode kompilasi-C lebih disukai daripada loop Python.
Meski sudah terlambat bagi Anda, namun untuk referensi di masa mendatang: Menggunakan numba ( 1 ) adalah cara termudah sampai numpy mengimplementasikannya. Jika Anda menggunakan distribusi python anaconda, itu seharusnya sudah diinstal. Kode tersebut akan di-compile sehingga menjadi cepat.
lalu:
sumber
xrange
perlu diubah untukrange
.enumerate
, sepertifor i, v in enumerate(vec):
;if v == item: return i
. (Ini bukan ide yang baik dengan Python <= 2.7, di manaenumerate
membuat daftar daripada iterator dasar.)Saya telah membuat patokan untuk beberapa metode:
argwhere
nonzero
seperti dalam pertanyaan.tostring()
seperti dalam jawaban @Rob ReilinkKode Python dan Fortran tersedia. Saya melewatkan yang tidak menjanjikan seperti mengonversi ke daftar.
Hasil pada skala log. Sumbu X adalah posisi jarum (diperlukan waktu lebih lama untuk mengetahui apakah jarum berada jauh di bawah larik); nilai terakhir adalah jarum yang tidak ada dalam larik. Sumbu Y adalah waktu untuk menemukannya.
Array memiliki 1 juta elemen dan pengujian dijalankan 100 kali. Hasil masih sedikit berfluktuasi, tetapi tren kualitatifnya jelas: Python dan f2py berhenti pada elemen pertama sehingga skalanya berbeda. Python menjadi terlalu lambat jika jarumnya tidak di 1% pertama, sedangkan
f2py
cepat (tetapi Anda perlu mengkompilasinya).Singkatnya, f2py adalah solusi tercepat , terutama jika jarum muncul cukup awal.
Ini tidak dibangun yang mengganggu, tetapi sebenarnya hanya 2 menit kerja. Tambahkan ini ke file bernama
search.f90
:Jika Anda mencari sesuatu selain
integer
, ubah saja tipenya. Kemudian kompilasi menggunakan:setelah itu Anda dapat melakukannya (dari Python):
sumber
f2py
lebih lambat untuk 1 item dari 10?Anda bisa mengonversi array boolean menjadi string Python menggunakan
array.tostring()
dan kemudian menggunakan metode find ():Ini memang melibatkan penyalinan data, karena string Python harus tetap. Keuntungannya adalah Anda juga dapat mencari, misalnya, tepi naik dengan menemukan
\x00\x01
sumber
Dalam kasus array yang diurutkan
np.searchsorted
bekerja.sumber
Saya pikir Anda telah mengalami masalah di mana metode yang berbeda dan beberapa pengetahuan apriori tentang array akan sangat membantu. Jenis hal di mana Anda memiliki probabilitas X untuk menemukan jawaban Anda dalam persen Y pertama dari data. Memecah masalah dengan harapan menjadi beruntung kemudian melakukan ini dengan python dengan pemahaman daftar bersarang atau semacamnya.
Menulis fungsi C untuk melakukan kekerasan ini juga tidak terlalu sulit menggunakan ctypes .
Kode C yang saya retas bersama (index.c):
dan python:
dan saya mendapatkan 92.
Bungkus python menjadi fungsi yang tepat dan begitulah.
Versi C jauh (~ 20x) lebih cepat untuk seed ini (peringatan saya tidak baik dengan waktu)
sumber
@tal sudah menyajikan
numba
fungsi untuk menemukan indeks pertama tetapi itu hanya berfungsi untuk array 1D. Dengannp.ndenumerate
Anda juga dapat menemukan indeks pertama dalam array dimensi arbitar:Contoh kasus:
Pengaturan waktu menunjukkan bahwa kinerjanya mirip dengan solusi tals :
sumber
array
sebelum memasukkannya ke dalamnp.ndenumerate
, sehingga sumbu minat Anda muncul lebih dulu.np.argwhere
) hingga 717ns (solusi Anda), keduanya untuk larik bentuk(3000000, 12)
).Jika daftar Anda diurutkan , Anda dapat mencapai pencarian indeks yang sangat cepat dengan paket 'bisect'. Ini adalah O (log (n)) bukan O (n).
menemukan x dalam larik a, pasti lebih cepat dalam kasus yang diurutkan daripada rutin C yang melewati semua elemen pertama (untuk daftar yang cukup panjang).
Terkadang baik untuk mengetahuinya.
sumber
>>> cond = "import numpy as np;a = np.arange(40)"
timeit("np.searchsorted(a, 39)", cond)
bekerja selama 3,47867107391 detik.timeit("bisect.bisect(a, 39)", cond2)
bekerja selama 7,0661458969116 detik. Sepertinyanumpy.searchsorted
lebih baik untuk array yang diurutkan (setidaknya untuk int).Sejauh yang saya tahu hanya np.any dan np.all pada array boolean yang dihubung pendek.
Dalam kasus Anda, numpy harus melalui seluruh array dua kali, sekali untuk membuat kondisi boolean dan kedua kalinya untuk menemukan indeks.
Rekomendasi saya dalam hal ini adalah menggunakan cython. Saya pikir seharusnya mudah untuk menyesuaikan contoh untuk kasus ini, terutama jika Anda tidak memerlukan banyak fleksibilitas untuk tipe dan bentuk yang berbeda.
sumber
Saya membutuhkan ini untuk pekerjaan saya jadi saya belajar sendiri Python dan antarmuka C Numpy dan menulis sendiri. http://pastebin.com/GtcXuLyd Ini hanya untuk array 1-D, tetapi bekerja untuk sebagian besar tipe data (int, float, atau string) dan pengujian telah menunjukkan itu lagi sekitar 20 kali lebih cepat dari pendekatan yang diharapkan dalam Python murni- numpy.
sumber
Masalah ini dapat diselesaikan secara efektif dalam numpy murni dengan memproses array dalam potongan:
Array diproses dalam potongan ukuran
step
. Semakinstep
lama langkahnya, semakin cepat pemrosesan array-nol (kasus terburuk). Semakin kecil nilainya, semakin cepat pemrosesan larik dengan bukan nol di awal. Triknya adalah memulai dengan yang kecilstep
dan meningkatkannya secara eksponensial. Selain itu, tidak perlu menaikkannya di atas ambang batas karena manfaat yang terbatas.Saya telah membandingkan solusi dengan solusi ndarary.nonzero dan numba murni terhadap 10 juta array float.
Dan hasil di mesin saya:
Murni
ndarray.nonzero
pasti lebih longgar. Solusi numba sekitar 5 kali lebih cepat untuk kasus terbaik. Ini sekitar 3 kali lebih cepat dalam kasus terburuk.sumber
Jika Anda mencari elemen bukan nol pertama, Anda dapat menggunakan peretasan berikut:
Ini adalah solusi "numpy-pure" yang sangat cepat tetapi gagal untuk beberapa kasus yang dibahas di bawah.
Solusinya mengambil keuntungan dari kenyataan bahwa hampir semua representasi nol untuk tipe numerik terdiri dari
0
byte. Ini berlaku untuk numpybool
juga. Dalam versi numpy terbaru,argmax()
fungsi menggunakan logika hubung singkat saat memprosesbool
tipe. Ukurannyabool
1 byte.Jadi, seseorang perlu:
bool
. Tidak ada salinan yang dibuatargmax()
untuk menemukan byte bukan-nol pertama menggunakan logika hubung singkat//
) offset dengan ukuran elemen tunggal yang dinyatakan dalam byte (x.itemsize
)x[idx]
sebenarnya bukan nol untuk mengidentifikasi kasus ketika tidak ada bukan nolSaya telah membuat beberapa patokan terhadap solusi numba dan membangunnya
np.nonzero
.Hasil di mesin saya adalah:
Solusinya 33% lebih cepat dari numba dan ini "numpy-pure".
Kerugiannya:
object
float
ataudouble
perhitungansumber
x
sebelum meneleponnonzero()
. Ini mungkin akan lebih lambat daripada numba tetapi ** tidak akan ** mencari seluruh larik sambil mencari entri nol pertama sehingga mungkin cukup cepat untuk kebutuhan Anda.Sebagai pengguna matlab lama saya telah mencari solusi yang efisien untuk masalah ini cukup lama. Akhirnya, termotivasi oleh diskusi proposisi di utas ini, saya telah mencoba untuk menemukan solusi yang menerapkan API yang mirip dengan apa yang disarankan di sini , untuk saat ini hanya mendukung array 1D.
Anda akan menggunakannya seperti ini
Operator kondisi yang didukung adalah: cmp_equal, cmp_not_equal, cmp_larger, cmp_smaller, cmp_larger_eq, cmp_smaller_eq. Untuk efisiensi, ekstensi ditulis dalam c.
Anda dapat menemukan sumber, tolok ukur, dan detail lainnya di sini:
https://pypi.python.org/pypi?name=py_find_1st&:action=display
untuk digunakan dalam tim kami (anaconda di linux dan macos) Saya telah membuat penginstal anaconda yang menyederhanakan penginstalan, Anda dapat menggunakannya seperti yang dijelaskan di sini
https://anaconda.org/roebel/py_find_1st
sumber
Hanya catatan bahwa jika Anda melakukan urutan pencarian, perolehan kinerja dari melakukan sesuatu yang pintar seperti mengonversi ke string, mungkin hilang di loop luar jika dimensi pencarian tidak cukup besar. Lihat bagaimana kinerja iterasi find1 yang menggunakan trik konversi string yang diusulkan di atas dan find2 yang menggunakan argmax di sepanjang sumbu dalam (ditambah penyesuaian untuk memastikan non-match menghasilkan -1)
keluaran
Meskipun demikian, penemuan yang ditulis dalam C setidaknya akan sedikit lebih cepat daripada salah satu pendekatan ini
sumber
bagaimana dengan ini
sumber
where(array==item)[0][0]
dari pertanyaan ...Anda dapat mengubah array Anda menjadi
list
dan menggunakanindex()
metodenya:Sejauh yang saya tahu, ini adalah metode terkompilasi C.
sumber
timeit()
array 10.000 bilangan bulat - mengubah ke daftar sekitar 100 kali lebih lambat! Saya lupa bahwa struktur data yang mendasari untuk array numpy sangat berbeda dari daftar ..