Pregunta

Estoy intentando agrupar usando DBSCAN (implementación de scikit learn) y datos de ubicación.Mis datos están en formato de matriz np, pero para usar DBSCAN con la fórmula de Haversine necesito crear una matriz de distancia.Recibo el siguiente error cuando intento hacer esto (un error de 'módulo' no invocable). Por lo que he leído en línea, este es un error de importación, pero estoy bastante seguro de que ese no es mi caso.He creado mi propia fórmula de distancia haversine, pero estoy seguro de que el error no se debe a esto.

Estos son mis datos de entrada, una matriz 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 ]]

Y esta es la línea de código que genera errores.

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

Este es el mensaje de error:

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

Importo scipy como sp.(importar scipy como sp)

¿Fue útil?

Solución

Consulte la respuesta de @TommasoF.Esta respuesta es incorrecta: pdist permite elegir una función de distancia personalizada.Eliminaré la respuesta una vez que ya no sea elegida como la respuesta correcta.

Simplemente scipy's pdist no permite pasar en una función de distancia personalizada.Como puedes leer en el documentos, tiene algunas opciones, pero la distancia lateral no está dentro de la lista de métricas admitidas.

(Matlab pdist Sin embargo, admite la opción, consulte aquí)

es necesario hacer el cálculo "manualmente", es decircon bucles, algo como esto funcionará:

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.        ]]

Sólo como referencia, se puede encontrar una implementación en Python de Haverside. aquí.

Otros consejos

Con Scipy puede definir una función de distancia personalizada según lo sugerido por la documentación en este enlace y reportado aquí por conveniencia:

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()))

Aquí denuncia mi versión del código inspirado en el código de este enlace :

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

y llamando de la siguiente manera:

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

En mi implementación, la matriz A tiene la primera columna los valores de longitud y como la segunda columna los valores de latitud expresados en grados decimales.

Ahora puede agrupar datos espaciales de latitud y longitud con DBSCAN de scikit-learn y la métrica haversine sin precalcular una matriz de distancia usando scipy.

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

Esto viene de este tutorial en agrupación de datos espaciales con scikit-learn DBSCAN.En particular, observe que el eps El valor es 2 km dividido por 6371 (radio de la Tierra en km) para convertirlo a radianes.Además, observe que .fit() toma coordenadas en unidades de radianes para la métrica haversine.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top