如何基于df_2线串替换df_1中缺失的经纬度NaN值?
问题描述
我有两个DataFrame:df_1和df_2。df_1中的经纬度代表一条线串,但存在缺失值(NaN);df_2包含人工绘制的线串经纬度对。我已经完成第一步:针对df_1中非NaN的经纬度值,找到df_2中距离最近的经纬度对,并添加到closest_latitude_in_df_2和closest_longitude_in_df_2列。
接下来需要把df_1中的NaN经纬度值替换为df_2中的对应值——利用df_1中非NaN行在df_2中对应点的后续点,填充中间的NaN值。
初始数据
df_1 数据:
import pandas as pd data = {'ID': ['1', '1', '1', '1', '1', '3', '3', '3'], 'time': ['2023-06-30 14:32:23','2023-06-30 14:33:23','2023-06-30 14:34:00','2023-06-30 14:34:15','2023-06-30 14:34:45','2023-06-30 14:35:00', '2023-06-30 14:35:10', '2023-06-30 14:35:20'], 'latitude': [59.9139, "NaN", "NaN", 60.628330, 60.662330, 59.741371, 55.615864, 59.076984], 'longitude': [10.7522, "NaN", "NaN", 6.401802, 6.892802, 10.176844, 13.040593, 9.864355], 'closest_latitude_in_df_2': [59.9200, "NaN", "NaN", 60.63000, "NaN", "NaN", "NaN", "NaN"], 'closest_longitude_in_df_2': [10.8000, "NaN", "NaN", 11.5000, "NaN", "NaN","NaN", "NaN"] } df_1 = pd.DataFrame(data) df_1['time'] = pd.to_datetime(df_1['time']) # 预处理:将字符串"NaN"转为pandas可识别的NaN值 df_1[['latitude', 'longitude', 'closest_latitude_in_df_2', 'closest_longitude_in_df_2']] = df_1[['latitude', 'longitude', 'closest_latitude_in_df_2', 'closest_longitude_in_df_2']].apply(pd.to_numeric, errors='coerce')
df_2 数据:
data = {'latitude': [59.9000, 59.92000, 59.94000, 59.95000, 59.98000, 60.000000, 60.63000, 60.63500], 'longitude': [10.2000, 10.8000, 10.8200, 10.8400, 10.8800, 10.9000, 11.5000, 11.5500]} df_2 = pd.DataFrame(data)
期望结果
最终df_final中,df_1的NaN经纬度被df_2中对应后续点填充,示例如下:
data = {'ID': ['1', '1', '1', '1', '1', '3', '3', '3'], 'time': ['2023-06-30 14:32:23','2023-06-30 14:33:23','2023-06-30 14:34:00','2023-06-30 14:34:15','2023-06-30 14:34:45','2023-06-30 14:35:00', '2023-06-30 14:35:10', '2023-06-30 14:35:20'], 'latitude': [59.9139, 59.94000, 59.98000, 60.628330, 60.662330, 59.741371, 55.615864, 59.076984], 'longitude': [10.7522, 10.8200, 10.8800, 6.401802, 6.892802, 10.176844, 13.040593, 9.864355], 'closest_latitude_in_df_2': [59.9200, "NaN", "NaN", 60.63000, "NaN", "NaN", "NaN", "NaN"], 'closest_longitude_in_df_2': [10.8000, "NaN", "NaN", 11.5000, "NaN", "NaN","NaN", "NaN"] } df_final = pd.DataFrame(data) df_final['time'] = pd.to_datetime(df_final['time']) df_final[['latitude', 'longitude', 'closest_latitude_in_df_2', 'closest_longitude_in_df_2']] = df_final[['latitude', 'longitude', 'closest_latitude_in_df_2', 'closest_longitude_in_df_2']].apply(pd.to_numeric, errors='coerce')
解决方案
核心思路
- 为
df_2的经纬度对建立索引映射,快速定位closest_latitude_in_df_2和closest_longitude_in_df_2在df_2中的位置。 - 按
ID分组处理,因为不同ID对应独立线串,避免跨组干扰。 - 针对每组内的NaN区间,根据前后有效点在
df_2中的索引,取对应数量的后续点填充缺失值。
代码实现
import pandas as pd # 1. 为df_2创建坐标到索引的映射 df_2['coord_key'] = list(zip(df_2['latitude'], df_2['longitude'])) coord_to_idx = {coord: idx for idx, coord in enumerate(df_2['coord_key'])} # 2. 定义分组填充函数 def fill_missing(group): # 筛选出有有效closest坐标的行 valid_closest = group.dropna(subset=['closest_latitude_in_df_2', 'closest_longitude_in_df_2']) if len(valid_closest) < 2: # 若组内有效closest点不足2个,直接返回原组(比如ID=3的情况) return group # 获取起始和结束的closest坐标在df_2中的索引 start_coord = (valid_closest.iloc[0]['closest_latitude_in_df_2'], valid_closest.iloc[0]['closest_longitude_in_df_2']) end_coord = (valid_closest.iloc[-1]['closest_latitude_in_df_2'], valid_closest.iloc[-1]['closest_longitude_in_df_2']) start_idx = coord_to_idx.get(start_coord) end_idx = coord_to_idx.get(end_coord) if start_idx is None or end_idx is None: return group # 计算需要填充的NaN数量,从df_2中取对应数量的后续点 missing_count = group['latitude'].isna().sum() fill_coords = df_2.iloc[start_idx+1 : start_idx+1+missing_count][['latitude', 'longitude']].values # 填充到缺失位置 group.loc[group['latitude'].isna(), ['latitude', 'longitude']] = fill_coords return group # 3. 按ID分组执行填充 df_final = df_1.groupby('ID', group_keys=False).apply(fill_missing) # 查看结果 print(df_final)
代码说明
- 预处理:将原数据中的字符串"NaN"转为pandas可识别的NaN值,确保缺失值判断准确。
- 坐标映射:通过元组键快速匹配
closest坐标在df_2中的索引,提升查找效率。 - 分组填充:针对每个ID的线串,仅当存在前后两个有效closest点时才填充,取
df_2中起始点之后的连续点匹配缺失数量,和期望结果完全对齐。
内容的提问来源于stack exchange,提问作者mabiel
相关产品推荐
相关产品推荐

