Пошаговая трансляция произвольной функции в numpy - PullRequest
1 голос
/ 08 октября 2019

У меня есть матрица векторов, где каждая строка является вектором. Я хочу взять среднее значение всех векторов, а затем вычислить косинусное расстояние между каждым вектором и это среднее значение, возвращая массив расстояний.

>>> x = arange(1,10).reshape(3,3)
array([[1, 2, 3],
   [4, 5, 6],
   [7, 8, 9]])
>>> m = x.mean(0)
array([4., 5., 6.])

Значения косинуса следующие:

>>> from scipy.spatial.distance import cosine
cosine([1,2,3], [4,5,6])
0.0253681538029239
>>> cosine([4,5,6], [4,5,6])
0.0
>>> cosine([7,8,9], [4,5,6])
0.001809107314273195

Поэтому я хочу написать функцию f такую, что

>>> f(x, m)
array([0.0253681538029239, 0.0, 0.001809107314273195])

(или транспонирование такого массива. Это не имеет значения.)

Что является наиболееэффективный, самый офигительный способ написать f? Кажется, что хитрость заключается в том, чтобы получить правильную трансляцию через функцию cosine, но я не понял, как это сделать. Следующее не работает.

>>> from numpy import frompyfunc
>>> f = frompyfunc(cosine, 2, 1)
>>> f(x, m)
array([[0.0, 0.0, 0.0],
       [0.0, 0.0, 0.0],
       [0.0, 0.0, 0.0]], dtype=object)

(похоже, здесь numpy применяет cosine поэлементно, а не по строкам.)

Есть ли способ сделать этобез записи for -loop?


Похоже, это возможно с apply_along_axis.

>>> from numpy import apply_along_axis
>>> from functools import partial
>>> g = partial(cosine, m)
>>> apply_along_axis(g, 1, x)
array([0.02536815, 0.        , 0.00180911])

Это самый эффективный способ?

Ответы [ 2 ]

2 голосов
/ 08 октября 2019

Вам нужно изменить свой средний массив, чтобы он был 2D.

>>> from scipy.spatial.distance import cdist
>>> cdist(x, m.reshape(1, -1), metric='cosine')
array([[2.53681538e-02],
   [2.22044605e-16],
   [1.80910731e-03]])
1 голос
/ 08 октября 2019

Угадайте, что трюк заключается в использовании cdist, который работает с двумерными массивами в векторизованном виде, чтобы получить нам эти косинусные расстояния. Таким образом, одним из способов будет -

In [59]: from scipy.spatial.distance import cosine

In [61]: cdist(x,x.mean(0,keepdims=True),'cosine')
Out[61]: 
array([[2.53681538e-02],
       [2.22044605e-16],
       [1.80910731e-03]])

что keepdims позволяет вводу быть 2D и, следовательно, делает его совместимым с требованиями ввода cdist.

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