Эффективная оценка функции в каждой ячейке массива 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])

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

Я также проверил большие образцы, и улучшение пропорционально. Для сравнения производительности других методов, см. Этот пост