在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)
解决方案
编辑:here's a simple notebook example
一种一般方法,假设您有一个包含点的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查找‘end’坐标,然后使用square.coords
列作为第一个参数,将geopyvincenty()
函数应用于输入列中的每一行。这是因为该函数是按从右到左的列顺序应用的。
def get_distance(col):
end = df.ix[col.name]['coords']
return df['coords'].apply(vincenty, args=(end,), ellipsoid='WGS-84')
现在我们可以计算所有距离了。
我们调换了DataFrame(.T
),因为我们将用来检索距离的loc[]
方法引用索引标签、行标签。但是,我们内部Apply函数(见上文)使用检索到的值填充一列
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
。PANASapply
文档可能很有用,特别是在使用args
传递位置参数方面(您需要最新的PANAS版本才能正常工作)。
此代码尚未分析,而且可能有更快的方法来完成,但对于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
相关文章