इस फ़ंक्शन को गति देने के बारे में कोई सुझाव?

def smooth_surface(z,c):
    hph_arr_list = []
    for x in xrange(c,len(z)-(c+1)):
        new_arr = np.hstack(z[x-c:x+c])
        hph_arr_list.append(np.percentile(new_arr[((new_arr >= np.percentile(new_arr,15)) & (new_arr <= np.percentile(new_arr,85)))],99))
    return np.array(map(float,hph_arr_list))

वेरिएबल z की लंबाई ~15 मिलियन है और c विंडो साइज + और - का मान है। फ़ंक्शन मूल रूप से एक स्लाइडिंग विंडो है जो प्रति पुनरावृत्ति पर्सेंटाइल मान की गणना करता है। किसी भी सहायता की सराहना की जाएगी! z सरणियों की एक सरणी है (इसलिए np.hstack)। शायद कोई विचार अगर numba इससे मदद करेगा। यदि हां, तो कैसे कार्यान्वित करें?

1
hockey5692 18 जून 2020, 19:39

1 उत्तर

सबसे बढ़िया उत्तर

गणना का धीमा भाग रेखा np.percentile(new_arr[((new_arr >= np.percentile(new_arr,15)) & (new_arr <= np.percentile(new_arr,85)))],99) प्रतीत होता है। यह छोटे सरणियों पर अप्रत्याशित रूप से धीमी np.percentile के साथ-साथ कई मध्यवर्ती सरणियों के निर्माण के कारण है।

चूंकि new_arr वास्तव में काफी छोटा है, इसलिए इसे केवल सॉर्ट करना और इंटरपोलेशन स्वयं करना बहुत तेज़ है। इसके अलावा, numba भी गणना को गति देने में मदद कर सकता है।

@njit #Use @njit instead of @jit to increase speed
def filter(arr):
    arr = arr.copy() # This line can be removed to modify arr in-place
    arr.sort()
    lo = int(math.ceil(len(arr)*0.15))
    hi = int(len(arr)*0.85)
    interp = 0.99 * (hi - 1 - lo)
    interp = interp - int(interp)
    assert lo <= hi-2
    return arr[hi-2]* (1.0 - interp) + arr[hi-1] * interp

यह कोड मेरी मशीन पर आकार 20 के सरणियों के साथ 160 गुना तेज है और उसी परिणाम का उत्पादन करना चाहिए।

अंत में, आप numba में स्वचालित समानांतरीकरण का उपयोग करके smooth_surface को भी गति दे सकते हैं (देखें यहां)। यहाँ एक परीक्षण न किया गया प्रोटोटाइप है:

@jit(parallel=True)
def smooth_surface(z,c):
    hph_arr = np.zeros(len(z)-(c+1)-c)
    for x in prange(c,len(z)-(c+1)):
        hph_arr[x-c] = filter(np.hstack(z[x-c:x+c]))
    return hph_arr
1
hockey5692 21 जून 2020, 15:40