如何基于最新date_recorded更新车辆坐标并计算距离
基于历史行驶数据更新车辆坐标并计算距离的实现方案
已知两批车辆的历史观测数据(含ID、观测时间、经纬度、行驶速度和方向),需基于每辆车最后一次观测的行驶状态(速度、方向),推算指定日期(如2016年6月27日)的经纬度坐标,进而计算该日期下车辆间的距离。
核心思路
完成需求需执行以下关键步骤:
- 统一时间格式,计算最后一次观测到目标日期的时长
- 结合地球地理坐标的近似换算,根据行驶方向和速度计算经纬度偏移量
- 更新车辆到目标日期的坐标
- 使用球面距离公式计算车辆间的实际距离
关键换算说明
- 纬度方向:每1度纬度约等于69英里(或111公里),南北方向直接对应纬度增减
- 经度方向:在北纬40°左右(示例数据的纬度范围),每1度经度约等于53英里(或85公里),东西方向对应经度增减(东移经度绝对值减小,西移则增大)
- 默认速度单位为英里/小时,若实际单位不同,需同步调整换算系数
代码实现
import pandas as pd from math import radians, sin, cos, sqrt, atan2 # ---------------------- 1. 数据初始化与预处理 ---------------------- # Car 1 数据 car1_data = { "id": ["id0120169", "id0386349", "id1962532", "id0335207", "id0273508"], "date_recorded": ["7/1/2016 9:05", "6/29/2016 22:26", "6/29/2016 2:47", "6/26/2016 22:29", "6/25/2016 19:19"], "longitude": [-73.99017334, -73.97213745, -73.91963959, -73.98487091, -73.99116516], "latitude": [40.75667953, 40.75746155, 40.80377579, 40.76160812, 40.75000763], "rate": [50, 67, 43, 35, 46], "direction": ["N", "E", "E", "S", "W"]} car1_df = pd.DataFrame(car1_data) # Car 2 数据 car2_data = { "id": ["id2681896", "id3308448", "id2108525", "id3952220", "id2771348"], "date_recorded": ["6/30/2016 23:59", "6/29/2016 19:33", "6/28/2016 20:50", "6/26/2016 21:07", "6/25/2016 18:46"], "longitude": [-73.9881286621093, -73.9656295776367, -73.9716567993164, -73.9820938110351, -73.9761657714843], "latitude": [40.7320289611816, 40.7527198791503, 40.7945442199707, 40.7694053649902, 40.7602424621582], "rate": [81, 76, 59, 48, 55], "direction": ["S", "E", "N", "W", "W"]} car2_df = pd.DataFrame(car2_data) # 将时间字段转为datetime类型 car1_df['date_recorded'] = pd.to_datetime(car1_df['date_recorded']) car2_df['date_recorded'] = pd.to_datetime(car2_df['date_recorded']) # 定义目标推算日期 target_date = pd.to_datetime("6/27/2016 00:00") # ---------------------- 2. 计算坐标偏移与更新 ---------------------- # 方向对应的经纬度变化系数(基于英里/小时换算) direction_coeff = { 'N': (0, 1/69), # 北:纬度增加 'S': (0, -1/69), # 南:纬度减少 'E': (1/53, 0), # 东:经度增加(西经绝对值减小) 'W': (-1/53, 0) # 西:经度减少(西经绝对值增大) } def update_coordinates(df, target_date): # 计算时间差(转换为小时) df['time_diff_hours'] = (target_date - df['date_recorded']).dt.total_seconds() / 3600 # 过滤目标日期早于最后观测时间的记录(无需推算) df = df[df['time_diff_hours'] >= 0].copy() # 计算行驶总距离(英里) df['distance_traveled'] = df['rate'] * df['time_diff_hours'] # 拆分方向对应的经纬度系数 df['lon_coeff'], df['lat_coeff'] = zip(*df['direction'].map(direction_coeff)) # 更新到目标日期的经纬度 df['target_longitude'] = df['longitude'] + df['distance_traveled'] * df['lon_coeff'] df['target_latitude'] = df['latitude'] + df['distance_traveled'] * df['lat_coeff'] return df # 执行坐标更新 car1_updated = update_coordinates(car1_df, target_date) car2_updated = update_coordinates(car2_df, target_date) # ---------------------- 3. 计算车辆间球面距离(Haversine公式) ---------------------- def haversine(lon1, lat1, lon2, lat2): # 将经纬度转换为弧度 lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2]) # Haversine公式计算球面距离 dlon = lon2 - lon1 dlat = lat2 - lat1 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 c = 2 * atan2(sqrt(a), sqrt(1-a)) # 地球平均半径(英里) r = 3956 return c * r # 示例:计算指定两辆车在目标日期的距离 car1_example = car1_updated[car1_updated['id'] == 'id0335207'].iloc[0] car2_example = car2_updated[car2_updated['id'] == 'id3952220'].iloc[0] distance = haversine( car1_example['target_longitude'], car1_example['target_latitude'], car2_example['target_longitude'], car2_example['target_latitude'] ) print(f"目标日期下两辆车的距离:{distance:.2f} 英里")
代码说明
- 数据预处理:将字符串时间转为datetime格式,方便计算时间差;自动过滤无需推算的车辆(目标日期早于最后观测时间)
- 坐标推算:根据方向确定经纬度变化方向,结合速度和时长计算行驶距离,再换算为经纬度偏移量
- 距离计算:采用Haversine公式计算球面距离,比平面距离更符合实际地理场景
注意事项:
- 若速度单位为公里/小时,需调整
direction_coeff中的换算系数(纬度每度111公里,北纬40度经度每度85公里) - 如需更高精度,可使用专业地理库(如
geopy)替代手动换算
内容的提问来源于stack exchange,提问作者David Kurtenbach
相关产品推荐
相关产品推荐

