Предложения по ускорению этой функции python? - PullRequest
1 голос
/ 18 июня 2020

Есть предложения, как ускорить эту функцию?

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 Ответ

1 голос
/ 20 июня 2020

Медленная часть вычислений выглядит как строка 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

Этот код в 160 раз быстрее с массивами размера 20 на моей машине и должен давать тот же результат.

Наконец, вы также можете ускорить smooth_surface, используя автоматическое c распараллеливание в numba (см. здесь для получения дополнительной информации). Вот непроверенный прототип:

@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
...