comparando columnas en dos marcos de datos pandas separados

Tengo dos marcos de datos, los cuales contienen columnas de latitud y longitud. Para cada entrada lat / lon en la primera ttwig de datos, quiero evaluar cada par lat / lon en la segunda ttwig de datos para determinar la distancia.

Por ejemplo:

 df1: df2:

      lat lon lat lon 
 0 38.32 -100.50 0 37.65 -97.87
 1 42.51 -97.39 1 33.31 -96.40
 2 33.45 -103.21 2 36.22 -100.01

 distancia entre 38.32, -100.50 y 37.65, -97.87
 distancia entre 38.32, -100.50 y 33.31, -96.40
 distancia entre 38.32, -100.50 y 36.22, -100.01
 distancia entre 42.51, -97.39 y 37.65, -97.87
 distancia entre 42.51, -97.39 y 33.31, -96.40
 ...y así...

No estoy seguro de cómo hacer esto.

¡Gracias por la ayuda!

Distancia euclidiana se calcula como

edpic

Puedes hacer esto con tus dos marcos de datos como este

((df1 - df2) ** 2).sum(1) ** .5 0 2.714001 1 9.253113 2 4.232363 dtype: float64 

Puede realizar una combinación cruzada para obtener todas las combinaciones de lat / lon, luego calcular la distancia utilizando una medida apropiada. Para hacerlo, puede usar el paquete geopy , que proporciona geopy.distance.vincenty y geopy.distance.great_circle . Ambos deben dar distancias válidas, con la vincenty dar resultados más precisos, pero ser computacionalmente más lento.

 from geopy.distance import vincenty # Function to compute distances. def get_lat_lon_dist(row): # Store lat/long as tuples for input into distance functions. latlon1 = tuple(row[['lat1', 'lon1']]) latlon2 = tuple(row[['lat2', 'lon2']]) # Compute the distance. return vincenty(latlon1, latlon2).km # Perform a cross-join to get all combinations of lat/lon. dist = pd.merge(df1.assign(k=1), df2.assign(k=1), on='k', suffixes=('1', '2')) \ .drop('k', axis=1) # Compute the distances between lat/longs dist['distance'] = dist.apply(get_lat_lon_dist, axis=1) 

Utilicé kilómetros como mis unidades en el ejemplo, pero se pueden especificar otras, por ejemplo:

 vincenty(latlon1, latlon2).miles 

La salida resultante:

  lat1 lon1 lat2 lon2 distance 0 38.32 -100.50 37.65 -97.87 242.709065 1 38.32 -100.50 33.31 -96.40 667.878723 2 38.32 -100.50 36.22 -100.01 237.080141 3 42.51 -97.39 37.65 -97.87 541.184297 4 42.51 -97.39 33.31 -96.40 1024.839512 5 42.51 -97.39 36.22 -100.01 733.819732 6 33.45 -103.21 37.65 -97.87 671.766908 7 33.45 -103.21 33.31 -96.40 633.751134 8 33.45 -103.21 36.22 -100.01 424.335874 

Editar

Como lo señaló @MaxU en los comentarios, puede usar una implementación de la fórmula de Haversine de forma similar para obtener un rendimiento adicional. Esto debería ser equivalente a la función geopy en geopy .

ACTUALIZACIÓN: como lo señala @root no tiene mucho sentido usar la métrica euclidiana en este caso, así que usemos sklearn.neighbors.DistanceMetric

 from sklearn.neighbors import DistanceMetric dist = DistanceMetric.get_metric('haversine') 

Primero podemos construir un DF con todas las combinaciones – (c) root :

 x = pd.merge(df1.assign(k=1), df2.assign(k=1), on='k', suffixes=('1', '2')) \ .drop('k',1) 

Cálculo de distancia vectorizado “haversine”

 x['dist'] = np.ravel(dist.pairwise(np.radians(df1),np.radians(df2)) * 6367) 

Resultado:

 In [86]: x Out[86]: lat1 lon1 lat2 lon2 dist 0 38.32 -100.50 37.65 -97.87 242.073182 1 38.32 -100.50 33.31 -96.40 667.993048 2 38.32 -100.50 36.22 -100.01 237.350451 3 42.51 -97.39 37.65 -97.87 541.605087 4 42.51 -97.39 33.31 -96.40 1026.006744 5 42.51 -97.39 36.22 -100.01 734.219411 6 33.45 -103.21 37.65 -97.87 671.274044 7 33.45 -103.21 33.31 -96.40 632.004981 8 33.45 -103.21 36.22 -100.01 424.140594 

Respuesta VIEJA:

IIUC puede usar la distancia de pares scipy.spatial.distance.pdist :

 In [32]: from scipy.spatial.distance import pdist In [43]: from itertools import combinations In [34]: X = pd.concat([df1, df2]) In [35]: X Out[35]: lat lon 0 38.32 -100.50 1 42.51 -97.39 2 33.45 -103.21 0 37.65 -97.87 1 33.31 -96.40 2 36.22 -100.01 

como Pandas.Serie:

 In [36]: s = pd.Series(pdist(X), index=pd.MultiIndex.from_tuples(tuple(combinations(X.index, 2)))) In [37]: s Out[37]: 0 1 5.218065 2 5.573240 0 2.714001 1 6.473801 2 2.156409 1 2 10.768287 0 4.883646 1 9.253113 2 6.813846 2 0 6.793791 1 6.811439 2 4.232363 0 1 4.582194 2 2.573810 1 2 4.636831 dtype: float64 

como Pandas.DataFrame:

 In [46]: s.rename_axis(['df1','df2']).reset_index(name='dist') Out[46]: df1 df2 dist 0 0 1 5.218065 1 0 2 5.573240 2 0 0 2.714001 3 0 1 6.473801 4 0 2 2.156409 5 1 2 10.768287 6 1 0 4.883646 7 1 1 9.253113 8 1 2 6.813846 9 2 0 6.793791 10 2 1 6.811439 11 2 2 4.232363 12 0 1 4.582194 13 0 2 2.573810 14 1 2 4.636831