如何在Pandas DataFrame中基于行列值新增坐标距离计算列?
为Pandas DataFrame添加坐标距离计算列
原始DataFrame
| index | H_Lat | H_Lon | W_Lat | W_Lon |
|---|---|---|---|---|
| 0 | 18.447259 | 73.896742 | 18.534579 | 73.819043 |
| 1 | 18.523069 | 73.842460 | 18.491357 | 73.851985 |
| 2 | 18.511014 | 73.864071 | NaN | NaN |
预期结果
| index | H_Lat | H_Lon | W_Lat | W_Lon | Distance |
|---|---|---|---|---|---|
| 0 | 18.447259 | 73.896742 | 18.534579 | 73.819043 | 12.678631 |
| 1 | 18.523069 | 73.842460 | 18.491357 | 73.851985 | 3.651333 |
| 2 | 18.511014 | 73.864071 | NaN | NaN | NaN |
实现方案
使用Haversine公式计算球面两点间的距离,以下提供两种实现方式:
方式1:逐行计算(直观易读)
通过apply遍历DataFrame每行,调用距离计算函数并处理NaN值:
import pandas as pd import numpy as np def haversine_distance(lat1, lon1, lat2, lon2): # 角度转弧度 lat1_rad = np.radians(lat1) lon1_rad = np.radians(lon1) lat2_rad = np.radians(lat2) lon2_rad = np.radians(lon2) # Haversine公式核心计算 dlat = lat2_rad - lat1_rad dlon = lon2_rad - lon1_rad a = np.sin(dlat/2)**2 + np.cos(lat1_rad) * np.cos(lat2_rad) * np.sin(dlon/2)**2 c = 2 * np.arcsin(np.sqrt(a)) return c * 6371 # 6371为地球平均半径(公里) # 构造目标DataFrame df = pd.DataFrame({ 'H_Lat': [18.447259, 18.523069, 18.511014], 'H_Lon': [73.896742, 73.842460, 73.864071], 'W_Lat': [18.534579, 18.491357, np.nan], 'W_Lon': [73.819043, 73.851985, np.nan] }) # 新增Distance列 df['Distance'] = df.apply( lambda row: haversine_distance(row['H_Lat'], row['H_Lon'], row['W_Lat'], row['W_Lon']) if pd.notna(row['W_Lat']) and pd.notna(row['W_Lon']) else np.nan, axis=1 )
方式2:向量化运算(高效推荐)
利用numpy向量化操作批量计算整列数据,避免逐行循环,处理大数据量时效率更高,且自动兼容NaN值:
import pandas as pd import numpy as np # 构造目标DataFrame df = pd.DataFrame({ 'H_Lat': [18.447259, 18.523069, 18.511014], 'H_Lon': [73.896742, 73.842460, 73.864071], 'W_Lat': [18.534579, 18.491357, np.nan], 'W_Lon': [73.819043, 73.851985, np.nan] }) # 批量转换为弧度 lat1_rad = np.radians(df['H_Lat']) lon1_rad = np.radians(df['H_Lon']) lat2_rad = np.radians(df['W_Lat']) lon2_rad = np.radians(df['W_Lon']) # 批量计算距离 dlat = lat2_rad - lat1_rad dlon = lon2_rad - lon1_rad a = np.sin(dlat/2)**2 + np.cos(lat1_rad) * np.cos(lat2_rad) * np.sin(dlon/2)**2 c = 2 * np.arcsin(np.sqrt(a)) # 赋值给Distance列 df['Distance'] = c * 6371
两种方式运行后,均可得到与预期一致的结果,第三行因缺失坐标值,Distance自动为NaN。
内容的提问来源于stack exchange,提问作者Bhavesh Neekhra
相关产品推荐
相关产品推荐

