2013-06-30 3 views
2

У меня заканчивается провал мозга, но я просто не могу заставить это работать. У меня есть массив расстояний:Вычислить квадратные расстояния от матрицы numpy

import numpy as np 
zvals = np.linspace(-5,5,10) 
d = np.array([(0,0,z) for z in zvals]) 

Я хочу вычислить квадратное расстояние точек в массиве. Без NumPy способ сделать эту работу:

d2 = np.array([np.dot(d[i,:],d[i,:]) for i in range(d.shape[0])]) 

Однако, я знаю , что должен быть какой-то способ сделать это с помощью всего одного вызова точка, не так ли? Это, как говорится, ни

d2 = np.dot(d,d.T) 

или

d2 = np.dot(d.T,d) 

не дают то, что я хочу. Я понимаю, что глупо, но, пожалуйста, просветите меня здесь. Благодаря!

+0

Hmmm.np.diag (np.dot (d, d.T)), похоже, работает. Есть ли способ лучше?? – Rick

ответ

6

Редактировать: Начиная с версии NumPy 1.9, inner1d может быть быстрее. (Благодаря Nuno Aniceto для указания этого):

In [9]: %timeit -n 1000000 inner1d(d,d) 
1000000 loops, best of 3: 1.39 µs per loop 

In [14]: %timeit -n 1000000 einsum('ij,ij -> i', d, d) 
1000000 loops, best of 3: 1.8 µs per loop 

PS. Всегда проверяйте ориентиры для себя на входах, похожих на ваш предполагаемый прецедент. Результаты могут различаться по разным причинам, таким как размер ввода, аппаратное обеспечение, ОС, версия Python, версия NumPy, компилятор и библиотеки (например, ATLAS, MKL, BLAS).


Если у вас есть версия NumPy 1.6 или лучше, вы могли бы использовать np.einsum:

In [40]: %timeit np.einsum('ij,ij -> i', d, d) 
1000000 loops, best of 3: 1.79 us per loop 

In [46]: from numpy.core.umath_tests import inner1d 

In [48]: %timeit inner1d(d, d) 
100000 loops, best of 3: 1.97 us per loop 

In [44]: %timeit np.sum(d*d, axis=1) 
100000 loops, best of 3: 5.39 us per loop 

In [41]: %timeit np.diag(np.dot(d,d.T)) 
100000 loops, best of 3: 7.2 us per loop 

In [42]: %timeit np.array([np.dot(d[i,:],d[i,:]) for i in range(d.shape[0])]) 
10000 loops, best of 3: 26.1 us per loop 
+0

Ничего себе. Раньше я не слышал об einsum. Благодарю. – Rick

+0

'np.einsum' всегда получает +1! Можете ли вы добавить тайминги против 'inner1d'? Я не могу сейчас это исправить, но я думаю, что это может быть серьезный соперник. – Jaime

+0

@Jaime: Спасибо, Хайме. Для меня это новое. – unutbu

1

Я не уверен, есть ли опрятный способ сложить метод обычных точек в более крупном массиве. Вместо этого я обычно делаю:

d2 = n.sum(d*d,axis=1) 

Д * d, конечно, стандартная операция скалярного произведения, так как это только поэлементно умножение всех элементов массива. Аргумент axis=1 суммируется вдоль второй оси (по горизонтали, когда печатается массив), что является второй частью операции с точечным продуктом.

Edit: Кроме того, игнорирование общей нежелательности метода, ваша линия

d2 = np.array([np.dot(d[i,:],d[i,:]) for i in range(d.shape[0])]) 

может быть просто

d2 = np.array([np.dot(row,row) for row in d]) 

, как Numpy массивы возвращают строки, а не отдельных элементов матрицы при использовании «для в синтаксисе массива.

+0

Ницца! Я оговорился, когда сказал, что хочу сделать np.dot. Я просто хочу чистое решение numpy, которое вы предоставили. Благодаря! – Rick

+0

Ответы unutbu - это еще лучший (и более быстрый!) Пример правильного использования синтаксиса numpy, который я только что проверил, и похоже, что метод np.sum немного медленнее, чем np.diag один и намного медленнее, чем einsum. – inclement

+0

Спасибо, что проверили это! – Rick

4

Функциональные функции Dot очень быстрые, и для действительно простых вещей можно даже бить np.einsum (это потрясающая функция, которую вы обязательно должны научиться использовать). У Numpy есть скрытый маленький драгоценный камень, inner1d, который делает точечный продукт с трансляцией по последним измерениям его аргументов. Вы можете использовать его следующим образом:

from numpy.core.umath_tests import inner1d 
inner1d(a, a) 
Смежные вопросы