2016-03-12 4 views
4

У меня есть список точек в numpy матрицы,Pythonic способ вычисления расстояния с использованием матриц numpy?

A = [[x11,x12,x13],[x21,x22,x23] ] 

и у меня есть точка происхождение o= [o1,o2,o3], из которого я должен вычислить расстояние для каждой точки,

A - o будет вычитать o из любой точки. В настоящее время я должен делать квадрат каждого атрибута и операции добавления, я делаю это в цикле for. Есть ли более интуитивный способ сделать это?

P.S: Я делаю приведенный выше расчет как приложение для кластеризации портов kmeans. Я вычислил центроиды, и теперь у меня есть компьютерное расстояние для каждой точки от центра тяжести.

input_mat = input_data_per_minute.values[:,2:5] 

scaled_input_mat = scale2(input_mat) 

k_means = cluster.KMeans(n_clusters=5) 

print 'training start' 
k_means.fit(scaled_input_mat) 
print 'training over' 

out = k_means.cluster_centers_ 

Я должен вычислить расстояние между input_mat и каждым кластером центроидом.

+0

Загляните в 'cdist' из' scipy'. – Divakar

ответ

0

Вы должны быть в состоянии сделать что-то вроде этого: (предполагая, что я прочитал ваш вопрос прямо;))

In [1]: import numpy as np 

In [2]: a = np.array([[11,12,13],[21,22,23]]) 

In [3]: o = [1,2,3] 

In [4]: a - o # just showing 
Out[4]: 
array([[10, 10, 10], 
     [20, 20, 20]]) 

In [5]: a ** 2 # just showing 
Out[5]: 
array([[121, 144, 169], 
     [441, 484, 529]]) 

In [6]: b = (a ** 2) + (a - o) 

In [7]: b 
Out[7]: 
array([[131, 154, 179], 
     [461, 504, 549]]) 

Numpy велика, поскольку она движется через массив поэлементно! Это означает, что 90%% времени вы можете перебирать массив без цикла. Использование for-loop вне массива также значительно медленнее.

3

Numpy решение:

Numpy велик с вещания, так что вы можете обмануть его, чтобы сделать все расстояния в один шаг. Но он будет потреблять много памяти в зависимости от количества точек и кластерных центров. Фактически он создаст массив number_of_points * number_of_cluster_centers * 3:

Сначала вам нужно немного узнать о вещании, я сыграю его сам и определю каждое измерение вручную.

Я начну с определения некоторых точек и центров для целей иллюстрации:

import numpy as np 

points = np.array([[1,1,1], 
        [2,1,1], 
        [1,2,1], 
        [5,5,5]]) 

centers = np.array([[1.5, 1.5, 1], 
        [5,5,5]]) 

Теперь я буду готовить эти массивы так, что я могу использовать Numpy вещания, чтобы получить расстояние в каждом измерении:

distance_3d = points[:,None,:] - centers[None,:,:] 

Эффект. Первое измерение теперь означает «метка», второе измерение - это «метка» центров, а третье измерение - координата. Вычитание состоит в том, чтобы получить расстояние в каждом измерении. Результат будет иметь форму:

(number_of_points, number_of_cluster_centers, 3) 

теперь это только вопрос применения формулы евклидового расстояния:

# Square each distance 
distance_3d_squared = distance_3d ** 2 

# Take the sum of each coordinates distance (the result will be 2D) 
distance_sum = np.sum(distance_3d_squared, axis=2) 

# And take the square root 
distance = np.sqrt(distance_sum) 

Для моих тестовых данных конечного результата является:

#array([[ 0.70710678, 6.92820323], 
#  [ 0.70710678, 6.40312424], 
#  [ 0.70710678, 6.40312424], 
#  [ 6.36396103, 0.  ]]) 

Таким образом, элемент distance[i, j] даст вам расстояние от i до центра j.

Резюме:

Вы можете поместить все это в одной строке:

distance2 = np.sqrt(np.sum((points[:,None,:] - centers[None,:,:]) ** 2, axis=2)) 

раствора SciPy (быстрее & короче):

или если у вас есть SciPy использование cdist:

from scipy.spatial.distance import cdist 
distance3 = cdist(points, centers) 

Результат всегда будет таким же, но cdist является самым быстрым для множества точек и центров.