Создание матрицы расстояний с использованием nparray с pdist и Squareform

StackOverflow https://stackoverflow.com//questions/22081503

Вопрос

Я пытаюсь выполнить кластеризацию, используя DBSCAN (реализация обучения scikit) и данные о местоположении.Мои данные представлены в формате массива np, но для использования DBSCAN с формулой Haversine мне нужно создать матрицу расстояний.Когда я пытаюсь это сделать, я получаю следующую ошибку (ошибка «модуль», которую нельзя вызвать). Судя по тому, что я читал в Интернете, это ошибка импорта, но я почти уверен, что это не мой случай.Я создал свою собственную формулу гаверсинусного расстояния, но уверен, что ошибка не в этом.

Это мои входные данные, массив np (ResultArray).

[[ 53.3252628   -6.2644198 ]
[ 53.3287395   -6.2646543 ]
[ 53.33321202  -6.24785807]
[ 53.3261015   -6.2598324 ]
[ 53.325291    -6.2644105 ]
[ 53.3281323   -6.2661467 ]
[ 53.3253074   -6.2644483 ]
[ 53.3388147   -6.2338417 ]
[ 53.3381102   -6.2343826 ]
[ 53.3253074   -6.2644483 ]
[ 53.3228188   -6.2625379 ]
[ 53.3253074   -6.2644483 ]]

И это строка кода, в которой возникает ошибка.

distance_matrix = sp.spatial.distance.squareform(sp.spatial.distance.pdist
(ResultArray,(lambda u,v: haversine(u,v))))

Это сообщение об ошибке:

File "Location.py", line 48, in <module>
distance_matrix = sp.spatial.distance.squareform(sp.spatial.distance.pdist
(ResArray,(lambda u,v: haversine(u,v))))
File "/usr/lib/python2.7/dist-packages/scipy/spatial/distance.py", line 1118, in pdist
dm[k] = dfun(X[i], X[j])
File "Location.py", line 48, in <lambda>
distance_matrix = sp.spatial.distance.squareform(sp.spatial.distance.pdist
(ResArray,(lambda u,v: haversine(u,v))))
TypeError: 'module' object is not callable

Я импортирую scipy как sp.(импортировать scipy как sp)

Это было полезно?

Решение

Пожалуйста, обратитесь к ответу @TommasoF.Этот ответ неверен: pdist позволяет выбрать пользовательскую функцию расстояния.Я удалю ответ, как только он больше не будет выбран в качестве правильного ответа.

Просто scipy's pdist не позволяет передать пользовательскую функцию расстояния.Как вы можете прочитать в документы, у вас есть несколько вариантов, но расстояние между хаверсайдами не входит в список поддерживаемых метрик.

(Малаб pdist поддерживает этот вариант, см. здесь)

расчет нужно делать «вручную», т.е.с циклами будет работать что-то вроде этого:

from numpy import array,zeros

def haversine(lon1, lat1, lon2, lat2):
    """  See the link below for a possible implementation """
    pass

#example input (your's, truncated)
ResultArray = array([[ 53.3252628, -6.2644198 ],
                     [ 53.3287395  , -6.2646543 ],
                     [ 53.33321202 , -6.24785807],
                     [ 53.3253074  , -6.2644483 ]])

N = ResultArray.shape[0]
distance_matrix = zeros((N, N))
for i in xrange(N):
    for j in xrange(N):
        lati, loni = ResultArray[i]
        latj, lonj = ResultArray[j]
        distance_matrix[i, j] = haversine(loni, lati, lonj, latj)
        distance_matrix[j, i] = distance_matrix[i, j]

print distance_matrix
[[ 0.          0.38666203  1.41010971  0.00530489]
 [ 0.38666203  0.          1.22043364  0.38163748]
 [ 1.41010971  1.22043364  0.          1.40848782]
 [ 0.00530489  0.38163748  1.40848782  0.        ]]

Для справки: реализацию Хаверсайда на Python можно найти. здесь.

Другие советы

С Scipy вы можете определить пользовательскую дистанционную функцию, как предложено документацией при этом Ссылка и сообщает здесь для удобства:

Y = pdist(X, f)
.
Computes the distance between all pairs of vectors in X using the user supplied 2-arity function f. For example, Euclidean distance between the vectors could be computed as follows:

dm = pdist(X, lambda u, v: np.sqrt(((u-v)**2).sum()))
.

Здесь я сообщаю о моей версии кода, вдохновленного в код из этого Ссылка :

from numpy import sin,cos,arctan2,sqrt,pi # import from numpy
# earth's mean radius = 6,371km
EARTHRADIUS = 6371.0

def getDistanceByHaversine(loc1, loc2):
    '''Haversine formula - give coordinates as a 2D numpy array of
    (lat_denter link description hereecimal,lon_decimal) pairs'''
    #      
    # "unpack" our numpy array, this extracts column wise arrays
    lat1 = loc1[1]
    lon1 = loc1[0]
    lat2 = loc2[1]
    lon2 = loc2[0]
    #
    # convert to radians ##### Completely identical
    lon1 = lon1 * pi / 180.0
    lon2 = lon2 * pi / 180.0
    lat1 = lat1 * pi / 180.0
    lat2 = lat2 * pi / 180.0
    #
    # haversine formula #### Same, but atan2 named arctan2 in numpy
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = (sin(dlat/2))**2 + cos(lat1) * cos(lat2) * (sin(dlon/2.0))**2
    c = 2.0 * arctan2(sqrt(a), sqrt(1.0-a))
    km = EARTHRADIUS * c
    return km
.

и звонить следующим образом:

D = spatial.distance.pdist(A, lambda u, v: getDistanceByHaversine(u,v))
.

В моем внедрении матрица A имеет в качестве первой столбцы значений долготы и в качестве второй колонны значения широты, выраженные в десятичных градусах.

Теперь вы можете кластеризовать пространственную широту-долготу, с помощью DBSCAN Scikit - DBSCAN и метрикой Haversine без предварительно перемешивания матрицы расстояния с использованием Scipy.

db = DBSCAN(eps=2/6371., min_samples=5, algorithm='ball_tree', metric='haversine').fit(np.radians(coordinates))
.

Это исходит из этого руководства на Кластеризация пространственных данных с Scikit-Survey dbscan .В частности, обратите внимание, что значение eps составляет 2 км, разделяется на 6371 (радиус земли в км), чтобы преобразовать его в радианы.Кроме того, обратите внимание, что .fit() принимает координаты в радианских единицах для метрики Haversine.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top