2017-04-03 108 views
3

我有兩個數據幀,它們都包含經度和緯度的列。對於第一個數據幀中的每個經度/緯度條目,我想評估第二個數據幀中的每個緯度/經度對以確定距離。比較兩個獨立的熊貓數據幀中的列

例如:

 
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 

distance between 38.32,-100.50 and 37.65,-97.87 
distance between 38.32,-100.50 and 33.31,-96.40 
distance between 38.32,-100.50 and 36.22,-100.01 
distance between 42.51,-97.39 and 37.65,-97.87 
distance between 42.51,-97.39 and 33.31,-96.40 
...and so on... 

我不知道如何去這樣做。

感謝您的幫助!

回答

4

Euclidean Distance作爲

edpic

爲此,您可以用你的兩個dataframes這樣

((df1 - df2) ** 2).sum(1) ** .5 

0 2.714001 
1 9.253113 
2 4.232363 
dtype: float64 
+2

作爲經緯度座標之間的直接測量,歐幾里得距離並沒有什麼意義。 – root

+0

@root非常好的一點。甚至沒有想到這一點。 – piRSquared

3

UPDATE計算:如@root注意它並沒有真正多大感覺在這種情況下使用歐幾里德度量,所以讓我們使用sklearn.neighbors.DistanceMetric

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

首先,我們可以建立一個DF與所有組合 - (c) root

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

矢量 「半正矢」 距離計算

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

結果:

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 

OLD答案:

IIUC你可以使用成對的距離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 

爲Pandas.Series:

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 

爲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 
+1

歐幾里得距離作爲緯度/長度座標之間的直接測量並不合理。 – root

+0

@root,這很有趣 - 與'vincenty'方法相比,'haversine'指標給我們提供了接近,但不完全相同的距離... – MaxU

+1

是的,半胱氨酸公式基於球形地球,但地球不是真是一個完美的領域;它在赤道周圍略胖(扁球體)。 vincenty公式解釋了這一點。在大多數情況下,半乳糖胺應該非常接近vincenty,尤其是相對較近的距離。全球兩側的點(對映點)會發生重大差異。 – root

3

您可以執行交叉聯接得到經緯度的所有組合,然後使用適當的度量來計算距離。爲此,您可以使用geopy包,該包提供geopy.distance.vincentygeopy.distance.great_circle。兩者都應該給出有效距離,vincenty給出更準確的結果,但計算速度較慢。

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) 

在示例中,我使用公里作爲單位,但也可以指定其他公里作爲單位。:

vincenty(latlon1, latlon2).miles 

輸出結果:

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 

編輯

正如在評論中指出的@MaxU,你可以在額外的性能類似的方式使用numpy implementation of the Haversine formula。這應該等於geopy中的great_circle函數。

+1

我認爲你可以使用[vectorized haversine公式](http://stackoverflow.com/a/29546836/5741205) – MaxU

+0

@MaxU:謝謝,我很快找到了一個haversine的實現,但只找到了一個純python。 – root

+0

根,謝謝。問題解決了! – user1985891