Для этого lambda
, fromfunction
отлично работает:
In [1]: foo = lambda i,j: (i-j)**2
In [2]: np.fromfunction(foo,(4,4))
Out[2]:
array([[0., 1., 4., 9.],
[1., 0., 1., 4.],
[4., 1., 0., 1.],
[9., 4., 1., 0.]])
fromfunction
генерирует «сетку» индексов из формы:
In [7]: np.indices((4,4))
Out[7]:
array([[[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]],
[[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3]]])
и передаетдве плоскости (1-е измерение) для вашей функции.Ваша функция, как написано, работает с массивами, такими как эти 2-мерные сетки.meshgrid
и mgrid
(и ogrid
) генерируют аналогичные индексы.
Но я также мог бы создать два массива напрямую и передать их foo
:
In [8]: foo(np.arange(4)[:,None], np.arange(4))
Out[8]:
array([[0, 1, 4, 9],
[1, 0, 1, 4],
[4, 1, 0, 1],
[9, 4, 1, 0]])
Эти два входных массива транслируются друг против друга так же, как это делают 2 плоскости в Out[7]
.По сути, они являются (4,1) и (4) -образными эквивалентами.
Обратите внимание, что в Python lambda
- это просто анонимная функция.Здесь я присвоил его переменной, дав ей имя (своего рода).Функция def
также может быть использована.
Так что, пока ваша функция работает с необходимыми массивами двумерных индексов, вам не нужно никакого специального кодирования.
Если функция работает только со скалярными значениями i
и j
, тогда вам придется прибегнуть к чему-то, что повторяется на уровне Python (в отличие от использования скомпилированных numpy
функций).
Версия со списком:
In [6]: np.array([[foo(i,j) for j in range(4)] for i in range(4)])
Out[6]:
array([[0, 1, 4, 9],
[1, 0, 1, 4],
[4, 1, 0, 1],
[9, 4, 1, 0]])
Мне скорее нравитсяfrompyfunc
, который будет использоваться как:
In [9]: f = np.frompyfunc(foo, 2,1)
In [10]: f(np.arange(4)[:,None], np.arange(4))
Out[10]:
array([[0, 1, 4, 9],
[1, 0, 1, 4],
[4, 1, 0, 1],
[9, 4, 1, 0]], dtype=object)
Обратите внимание, что он возвращает объект dtype.Это можно изменить с помощью astype
.Он также может быть передан в fromfunction
, если вы слишком 'ленивы', чтобы писать свои собственные передаваемые массивы I
и J
.
По моему опыту, подход frompyfunc
несколько быстрее, чем списокпонимание (примерно до 2х).С другой стороны, если foo
работает с массивами, как в [8], то соотношение скоростей больше похоже на 10x.Поэтому с точки зрения производительности вы будете счастливы, если сможете писать функции, работающие с целыми массивами, а не со скалярными индексами.