Bazen eğer olmayan deyimsel numpy kod yazmak gerekir gerçekten sen yerli Numpy ile yapamaz senin hesaplama hızlandırmak istiyoruz.
numba
Python kodunuzu düşük seviyeli C'ye derler. Çok sayıda numpy'nin kendisi genellikle C kadar hızlı olduğundan, probleminiz numpy ile yerel vektörleşmeye katkıda bulunmuyorsa, bu çoğunlukla yararlı olur. Bu bir örnektir (burada indekslerin bitişik ve sıralı olduğu varsayılmıştır, ayrıca örnek verilere de yansıtılır):
import numpy as np
import numba
# use the inflated example of roganjosh https://stackoverflow.com/a/58788534
data = [1.00, 1.05, 1.30, 1.20, 1.06, 1.54, 1.33, 1.87, 1.67]
index = [0, 0, 1, 1, 1, 1, 2, 3, 3]
data = np.array(data * 500) # using arrays is important for numba!
index = np.sort(np.random.randint(0, 30, 4500))
# jit-decorate; original is available as .py_func attribute
@numba.njit('f8[:](f8[:], i8[:])') # explicit signature implies ahead-of-time compile
def diffmedian_jit(data, index):
res = np.empty_like(data)
i_start = 0
for i in range(1, index.size):
if index[i] == index[i_start]:
continue
# here: i is the first _next_ index
inds = slice(i_start, i) # i_start:i slice
res[inds] = data[inds] - np.median(data[inds])
i_start = i
# also fix last label
res[i_start:] = data[i_start:] - np.median(data[i_start:])
return res
IPython'un %timeit
büyüsünü kullanan bazı zamanlamalar :
>>> %timeit diffmedian_jit.py_func(data, index) # non-jitted function
... %timeit diffmedian_jit(data, index) # jitted function
...
4.27 ms ± 109 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
65.2 µs ± 1.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Sorudaki güncellenmiş örnek verileri kullanarak bu sayılar (yani Python işlevinin çalışma zamanı ve JIT hızlandırmalı işlevin çalışma zamanı karşılaştırması)
>>> %timeit diffmedian_jit.py_func(data, groups)
... %timeit diffmedian_jit(data, groups)
2.45 s ± 34.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
93.6 ms ± 518 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Bu, hızlandırılmış kodu kullanarak küçük durumda 65x hızlanma ve daha büyük durumda 26x hızlanma (elbette yavaş döngüsel kodla karşılaştırıldığında) anlamına gelir. Diğer bir tersi ise (yerel numpy ile tipik vektörleştirmenin aksine) bu hıza ulaşmak için ek belleğe ihtiyacımız olmadı, tamamen optimize edilmiş ve derlenmiş düşük seviyeli kodla ilgili.
Yukarıdaki işlev, numpy int dizilerinin varsayılan olarak olduğunu varsayar; int64
bu aslında Windows için geçerli değildir. Bu yüzden bir alternatif, numba.njit
uygun zamanda tam zamanında derlemeyi tetikleyerek imzayı çağrıdan kaldırmaktır . Ancak bu, işlevin ilk yürütme sırasında derleneceği anlamına gelir, bu da zamanlama sonuçlarıyla karışabilir (temsili veri türlerini kullanarak işlevi bir kez manuel olarak yürütebiliriz veya sadece ilk zamanlama yürütmesinin çok daha yavaş olacağını kabul edebiliriz. yok sayılmak). Tam olarak derlemeyi tetikleyen bir imza belirterek tam olarak önlemeye çalıştım.
Her neyse, düzgün bir JIT durumunda ihtiyacımız olan dekoratör
@numba.njit
def diffmedian_jit(...):
Jit derleme işlevi için gösterdiğim yukarıdaki zamanlamaların yalnızca işlev derlendikten sonra geçerli olduğunu unutmayın. Bu ya tanımda (istekli derleme, açık bir imza iletildiğinde numba.njit
) ya da ilk fonksiyon çağrısı sırasında (tembel derleme ile, hiçbir imza iletilmediğinde numba.njit
) olur. Eğer fonksiyon sadece bir kez uygulanacaksa, bu yöntemin hızı için derleme süresi de dikkate alınmalıdır. Genellikle derleme + yürütme toplam süresi derlenmemiş çalışma zamanından daha azsa (yalnızca yerel python işlevinin çok yavaş olduğu yukarıdaki durumda doğrudur) derleme işlevlerine değer. Bu çoğunlukla derlenmiş işlevinizi birçok kez çağırdığınızda olur.
As max9111 bir yorumda kaydetti biri önemli özelliği numba
olan cache
anahtar kelime için jit
. Geçme cache=True
için numba.jit
, diske derlenen fonksiyonu depolar böylece uzun vadede orada ziyade recompiled yine yedek hangi çalışma zamanı verilen piton modülünün sonraki yürütme sırasında işlev yüklenecek söyledi.
scipy.ndimage.median
bağlantılı yanıtında öneri? Bana öyle geliyor ki, etiket başına eşit sayıda öğeye ihtiyaç duyuyor. Yoksa bir şey mi kaçırdım?