Эффективная оценка функции в каждой ячейке массива NumPy
Учитывая NumPy array A, что является самым быстрым/наиболее эффективным способом применения той же функции, f, до каждой ячейки?
-
Предположим, что мы будем назначать A (i, j) f (A (i, j)).
-
Функция f не имеет двоичного выхода, поэтому операции маскировки не помогут.
Является ли "очевидная" двойная итерация цикла (через каждую ячейку) оптимальным решением?
Ответы
Ответ 1
Вы можете просто vectorize использовать эту функцию, а затем применять ее непосредственно к массиву Numpy каждый раз, когда вам это нужно:
import numpy as np
def f(x):
return x * x + 3 * x - 2 if x > 0 else x * 5 + 8
f = np.vectorize(f) # or use a different name if you want to keep the original f
result_array = f(A) # if A is your Numpy array
Вероятно, лучше указать явный тип вывода непосредственно при векторизации:
f = np.vectorize(f, otypes=[np.float])
Ответ 2
Аналогичный вопрос: Сопоставление массива NumPy на месте.
Если вы можете найти ufunc для своего f(), вы должны использовать параметр out.
Ответ 3
Если вы работаете с числами и f(A(i,j)) = f(A(j,i))
, вы можете использовать scipy.spatial.distance.cdist, определяя f как расстояние между A(i)
и A(j)
.
Ответ 4
Я считаю, что нашел лучшее решение. Идея изменить функцию на универсальную функцию Python (см. Документацию), которая может выполнять параллельные вычисления под капотом.
Можно написать собственный настраиваемый ufunc
в C, который, безусловно, более эффективен, или вызвав np.frompyfunc
, который является встроенным фабричным методом. После тестирования это более эффективно, чем np.vectorize
:
f = lambda x, y: x * y
f_arr = np.frompyfunc(f, 2, 1)
vf = np.vectorize(f)
arr = np.linspace(0, 1, 10000)
%timeit f_arr(arr, arr) # 307ms
%timeit f_arr(arr, arr) # 450ms
Я также проверил большие образцы, и улучшение пропорционально. Для сравнения производительности других методов, см. Этот пост