Ваше использование signature
в порядке; ему просто нужно использовать broadcasting
:
In [374]: def norm(x, y):
...: return np.linalg.norm(x-y)
...:
In [376]: f = np.vectorize(norm, signature='(d),(d)->()')
In [377]:
In [377]: X = np.array([[1,1,1,1],
...: [2,2,2,2]])
...:
...: Y = np.array([[3,3,3,3],
...: [4,4,4,4]])
In [378]: f(X,Y)
Out[378]: array([4., 4.])
In [379]: f(X[:,None,:], Y[None,:,:])
Out[379]:
array([[4., 6.],
[2., 4.]])
Ваша функция сначала выполняет x-y
; Итак, давайте сосредоточимся на этом:
In [383]: f = np.vectorize(lambda x,y:x-y, signature='(d),(d)->(d)')
In [384]: f(X[:,None,:], Y[None,:,:])
Out[384]:
array([[[-2, -2, -2, -2],
[-3, -3, -3, -3]],
[[-1, -1, -1, -1],
[-2, -2, -2, -2]]])
, но нам не нужно vectorize
, чтобы сделать это:
In [385]: X[:,None,:]-Y[None,:,:]
Out[385]:
array([[[-2, -2, -2, -2],
[-3, -3, -3, -3]],
[[-1, -1, -1, -1],
[-2, -2, -2, -2]]])
norm
принимает параметр axis
; указание последнего дает тот же результат выполнения построчной калибровки c с vectorize
:
In [387]: np.linalg.norm(X[:,None,:]-Y[None,:,:], axis=-1)
Out[387]:
array([[4., 6.],
[2., 4.]])
Недостатком этого правильно «векторизованного» подхода является то, что транслируемая разница может получить очень большой, что приводит к ошибкам в памяти.
Так что np.vectorize
является чем-то полезным, когда функция не может использовать более быстрые методы скомпилированного массива. Но это не инструмент скорости. Это медленнее, чем более явная итерация. Добавление signature
интересно, но еще медленнее.
scipy.spatial.distance.pdist
- хороший инструмент для парных расстояний.