簡體   English   中英

在python中計算*多*組地理坐標之間的距離

[英]Calculating distance between *multiple* sets of geo coordinates in python

我正在努力計算組經緯度坐標之間的距離。 簡而言之,我發現了許多使用數學或地理的教程。 當我只想找到一組坐標(或兩個唯一位置)之間的距離時,這些教程非常有用。 但是,我的目標是掃描具有 400k 原始坐標和目標坐標組合的數據集。 下面列出了我使用的代碼的一個示例,但是當我的數組 > 1 條記錄時,我似乎遇到了錯誤。 任何有用的提示將不勝感激。 謝謝。

# starting dataframe is df

lat1 = df.lat1.as_matrix()
long1 = df.long1.as_matrix()
lat2 = df.lat2.as_matrix()
long2 = df.df_long2.as_matrix()

from geopy.distance import vincenty
point1 = (lat1, long1)
point2 = (lat2, long2)
print(vincenty(point1, point2).miles)

編輯: 這是一個簡單的筆記本示例

一種通用方法,假設您有一個包含點的 DataFrame 列,並且您想要計算所有這些點之間的距離(例如,如果您有單獨的列,首先將它們組合成(lon, lat)元組)。 命名新的列coords

import pandas as pd
import numpy as np
from geopy.distance import vincenty


# assumes your DataFrame is named df, and its lon and lat columns are named lon and lat. Adjust as needed.
df['coords'] = zip(df.lat, df.lon)
# first, let's create a square DataFrame (think of it as a matrix if you like)
square = pd.DataFrame(
    np.zeros(len(df) ** 2).reshape(len(df), len(df)),
    index=df.index, columns=df.index)

此函數使用輸入列名稱從df DataFrame 中查找我們的“結束”坐標,然后將 geopy vincenty()函數應用於輸入列中的每一行,使用square.coords列作為第一個參數。 這是有效的,因為該函數是從右到左按列應用的。

def get_distance(col):
    end = df.ix[col.name]['coords']
    return df['coords'].apply(vincenty, args=(end,), ellipsoid='WGS-84')

現在我們已准備好計算所有距離。
我們正在轉置 DataFrame ( .T ),因為我們將用來檢索距離的loc[]方法是指索引標簽,行標簽 然而,我們的內部應用函數(見上文)用檢索到的值填充一列

distances = square.apply(get_distance, axis=1).T

您的geopy值以公里為單位返回 (IIRC),因此您可能需要使用.meters.miles等將這些值轉換為您想要使用的任何單位。

像下面這樣的東西應該工作:

def units(input_instance):
    return input_instance.meters

distances_meters = distances.applymap(units)

您現在可以使用例如loc[row_index, column_index]索引距離矩陣。 您應該能夠很容易地適應上述內容。 您可能需要調整get_distance函數中的apply調用,以確保將正確的值傳遞給great_circle pandas apply docs 可能很有用,特別是在使用args傳遞位置參數方面(你需要一個最新的 pandas 版本才能工作)。

這段代碼沒有被分析,可能有更快的方法來完成,但對於 400k 距離計算應該相當快。

哦還有

我不記得 geopy 是否期望坐標為(lon, lat)(lat, lon) 我敢打賭是后者(嘆氣)。

更新這是截至 2021 年 5 月的工作腳本。

import geopy.distance
# geopy DOES use latlon configuration
df['latlon'] = list(zip(df['lat'], df['lon']))
square = pd.DataFrame(
    np.zeros((df.shape[0], df.shape[0])),
    index=df.index, columns=df.index
)

# replacing distance.vicenty with distance.distance
def get_distance(col):
    end = df.loc[col.name, 'latlon']
    return df['latlon'].apply(geopy.distance.distance,
                              args=(end,),
                              ellipsoid='WGS-84'
                             )

distances = square.apply(get_distance, axis=1).T

我最近不得不做類似的工作,我寫了一個我認為很容易理解和調整到您的需求的解決方案,但可能不是最好/最快的:

解決方案

它與 urschrei 發布的內容非常相似:假設您想要 Pandas DataFrame 中每兩個連續坐標之間的距離,我們可以編寫一個函數來處理每對點作為路徑起點終點,計算距離然后構造一個新的 DataFrame 作為回報:

import pandas as pd
from geopy import Point, distance
   
def get_distances(coords: pd.DataFrame,
                  col_lat='lat',
                  col_lon='lon',
                  point_obj=Point) -> pd.DataFrame:
    traces = len(coords) -1
    distances = [None] * (traces)
    for i in range(traces):
        start = point_obj((coords.iloc[i][col_lat], coords.iloc[i][col_lon]))
        finish = point_obj((coords.iloc[i+1][col_lat], coords.iloc[i+1][col_lon]))
        distances[i] = {
            'start': start,
            'finish': finish,
            'path distance': distance.geodesic(start, finish),
        }

    return pd.DataFrame(distances)

使用示例

coords = pd.DataFrame({
    'lat': [-26.244333, -26.238000, -26.233880, -26.260000, -26.263730],
    'lon': [-48.640946, -48.644670, -48.648480, -48.669770, -48.660700],
})

print('-> coords DataFrame:\n', coords)
print('-'*79, end='\n\n')

distances = get_distances(coords)
distances['total distance'] = distances['path distance'].cumsum()
print('-> distances DataFrame:\n', distances)
print('-'*79, end='\n\n')

# Or if you want to use tuple for start/finish coordinates:
print('-> distances DataFrame using tuples:\n', get_distances(coords, point_obj=tuple))
print('-'*79, end='\n\n')

輸出示例

-> coords DataFrame:
          lat        lon
0 -26.244333 -48.640946
1 -26.238000 -48.644670
2 -26.233880 -48.648480
3 -26.260000 -48.669770
4 -26.263730 -48.660700
------------------------------------------------------------------------------- 

-> distances DataFrame:
                                   start                             finish  \
0  26 14m 39.5988s S, 48 38m 27.4056s W   26 14m 16.8s S, 48 38m 40.812s W   
1      26 14m 16.8s S, 48 38m 40.812s W  26 14m 1.968s S, 48 38m 54.528s W   
2     26 14m 1.968s S, 48 38m 54.528s W     26 15m 36s S, 48 40m 11.172s W   
3        26 15m 36s S, 48 40m 11.172s W  26 15m 49.428s S, 48 39m 38.52s W   

           path distance         total distance  
0  0.7941932910049856 km  0.7941932910049856 km  
1  0.5943709651000332 km  1.3885642561050187 km  
2  3.5914909016938505 km   4.980055157798869 km  
3  0.9958396130609087 km   5.975894770859778 km  
------------------------------------------------------------------------------- 

-> distances DataFrame using tuples:
                       start                  finish         path distance
0  (-26.244333, -48.640946)    (-26.238, -48.64467)  0.7941932910049856 km
1      (-26.238, -48.64467)  (-26.23388, -48.64848)  0.5943709651000332 km
2    (-26.23388, -48.64848)     (-26.26, -48.66977)  3.5914909016938505 km
3       (-26.26, -48.66977)   (-26.26373, -48.6607)  0.9958396130609087 km
------------------------------------------------------------------------------- 

截至 5 月 19 日

對於處理多個地理定位數據的任何人,您可以修改上述代碼,但稍作修改以讀取數據驅動器中的 CSV 文件。 代碼將在標記的文件夾中寫入輸出距離。

import pandas as pd
from geopy import Point, distance
def get_distances(coords: pd.DataFrame,
   col_lat='lat',
              col_lon='lon',
              point_obj=Point) -> pd.DataFrame:
traces = len(coords) -1
distances = [None] * (traces)
for i in range(traces):
    start = point_obj((coords.iloc[i][col_lat], coords.iloc[i][col_lon]))
    finish = point_obj((coords.iloc[i+1][col_lat], coords.iloc[i+1][col_lon]))
    distances[i] = {
        'start': start,
        'finish': finish,
        'path distance': distance.geodesic(start, finish),
    }
output = pd.DataFrame(distances)
output.to_csv('geopy_output.csv')
return output

我使用了相同的代碼並為超過 50,000 個坐標生成了距離數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM