2016-03-30 2 views
0

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

data = np.array(
    [[2, 2, 3], 
    [4, 2, 4], 
    [1, 1, 4]]) 

Теперь, если моя контрольная точка является одной 1D NumPy массив как:

test = np.array([2,3,3]) 

я могу сделать что-то простое, как np.sqrt(np.sum((test-data)**2,axis=1)) вычислить расстояние от контрольной точки по отношению ко всем трем точкам данных.

Однако, если тест сам по себе является 2D массив точек, подлежащих испытанию, выше не работает, и я использую что-то вроде:

test = np.array([[2,3,3],[4,1,2]])  
for i in range(len(test)): 
    print np.sqrt(np.sum((test[i]-data)**2,axis=1)) 

>>> [ 1.   2.44948974 2.44948974] 
    [ 2.44948974 2.23606798 3.60555128] 

Для того, чтобы вычислить каждую точку в моем тестовом наборе против все точки в наборе данных. Кажется, что должен быть способ векторизации всей этой операции, чтобы получить (2,3) матрицу соответствующих расстояний обратно без внешней петли FOR

(Примечание: хотя этот конкретный пример относится к Евклидову Расстояние, I найти себя с аналогичными операциями, где я хотел бы выполнить операцию над всеми элементами одной матрицы с отдельными элементами другой матрицы, поэтому я надеюсь, что существует обобщенный способ создания таких проблем с использованием Numpy.)

+0

Это похоже на работу, но я обеспокоен использованием памяти на большее наборы данных, поскольку, по-видимому, требуется дублировать каждую контрольную точку N раз, где N - это число точек данных. Таким образом, если есть 1000 точек данных, мне нужно построить матрицу 2000 точек для проверки двух значений. 'print np.reshape (np.sqrt (np.sum (np.resape (np.repeat (test, len (data), axis = 0), (len (test) * len (data), Xdims)) - ml.repmat (данные, 2, 1)) ** 2, ось = 1)), (2, len (данные))).T' –

+2

Просто используйте [scipy's cdist] (http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.spatial.distance.cdist.html): 'from scipy.spatial.distance import cdist; out = cdist (тест, данные) '. Это суперэффективно. – Divakar

ответ

-2

Вы можете использовать список понимание:

result = np.array([np.sqrt(np.sum((t - data)**2, axis=1)) for t in test]) 
+0

Мое понимание заключается в том, что понимание - это просто фантастический цикл FOR. Моя надежда заключается в том, чтобы использовать скорость numpy и избегать цикла в Python. –

1

Что о np.meshgrid?

import numpy as np 

data = np.array(
    [[2, 2, 3], 
    [4, 2, 4], 
    [1, 1, 4]]) 


test = np.array([[2,3,3], 
       [4,1,2]]) 


d = np.arange(0,3) 
t = np.arange(0,2) 
d, t = np.meshgrid(d, t) 

# print test[t] 
# print data[d] 
print np.sqrt(np.sum((test[t]-data[d])**2,axis=2)) 

выход:

[[ 1.   2.44948974 2.44948974] 
[ 2.44948974 2.23606798 3.60555128]] 
+0

После просмотра сообщения Дивакара я отправился с 'scipy'' cdist'. – roadrunner66

2

использование broadcasting сделать:

from numpy.linalg import norm 
norm(data-test[:,None],axis=2) 

для

[ 1.   2.44948974 2.44948974] 
[ 2.44948974 2.23606798 3.60555128] 

Некоторые объяснения. Это легче понять, с различными формами, четыре и два очка для Exemple:

ens1 = np.array(
    [[2, 2, 3], 
    [4, 2, 4], 
    [1, 1, 4], 
    [2, 4, 5]]) 


ens2 = np.array([[2,3,3], 
       [4,1,2]]) 


In [16]: ens1.shape 
Out[16]: (4, 3) 

In [17]: ens2.shape 
Out[17]: (2, 3) 

Тогда:

In [21]: ens2[:,None].shape 
Out[21]: (2, 1, 3) 

добавить новое измерение. Теперь мы можем сделать 2x4 = 8 Вычеты:

In [22]: (ens1-ens2[:,None]).shape 
Out[22]: (2, 4, 3)  

и принять норму вдоль последней оси, на 8 расстояния:

In [23]: norm(ens1-ens2[:,None],axis=2) 
Out[23]: 
array([[ 1.  , 2.44948974, 2.44948974, 2.23606798], 
     [ 2.44948974, 2.23606798, 3.60555128, 4.69041576]])  
Смежные вопросы