Эффективная оценка функции в каждой ячейке массива NumPy - PullRequest
120 голосов
/ 09 октября 2011

Учитывая NumPy массив A , какой самый быстрый / самый эффективный способ применить такую ​​же функцию f каждая клетка?

  1. Предположим, что мы присвоим A (i, j) f (A (i, j)) .

  2. Функция f не имеет двоичного вывода, поэтому операции маскирования (ing) не помогут.

Является ли "очевидная" итерация двойного цикла (через каждую ячейку) оптимальным решением?

Ответы [ 4 ]

161 голосов
/ 09 октября 2011

Вы можете просто векторизовать функцию и затем применять ее непосредственно к массиву 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])
5 голосов
/ 10 октября 2011

Аналогичный вопрос: Отображение массива NumPy на место .Если вы можете найти ufunc для вашего f (), то вам следует использовать параметр out.

1 голос
/ 10 мая 2016

Если вы работаете с числами и f(A(i,j)) = f(A(j,i)), вы можете использовать scipy.spatial.distance.cdist , определяя f как расстояние между A(i) и A(j).

0 голосов
/ 16 мая 2019

Я считаю, что нашел лучшее решение. Идея изменить функцию на универсальную функцию 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...