Pandas interpolate插值未返回预期结果求助
船舶AIS数据时间插值后参数未变化的问题解决
问题背景
原始CSV数据格式如下(BaseDateTime代表相邻条目间的时间差,单位:秒):
MMSI,BaseDateTime,LAT,LON,SOG,COG 11,0,27.29237,-90.96787,0.1,195.7 11,360,27.29237,-90.96793,0.1,188.0 111, 0,27.3538,-94.6253,0.1,35.3 111,180,27.35376,-94.62543,0.1,225.5
目标是将不均匀时间间隔转换为每30秒一条记录,但现有代码运行后,时间维度符合要求,但LAT、LON、SOG、COG字段未产生合理插值变化,输出示例:
MMSI,BaseDateTime,Latitude,Longitude,SOG,COG 11,0.0,27.29237,-90.96787,0.1,195.7 11,30.0,27.29237,-90.96787,0.1,195.7 ... 11,360.0,27.29237,-90.96787,0.1,195.7
问题原因
核心错误在于时间索引的处理逻辑:
原代码直接将BaseDateTime(相邻时间差)转为timedelta作为索引,但resample需要基于连续的累计时间戳(即每个数据点对应的实际时间点),而非间隔值。比如MMSI=11的两条数据,实际时间点是0秒和360秒(0+360),但原代码把索引设为0秒和360秒的间隔值,导致resample时无法识别这两个点是时间轴上的起止点,插值只会沿用前值。
解决方案
修改代码,先为每个MMSI组计算累计时间戳,再基于累计时间轴进行resample和插值:
import pandas as pd import numpy as np def interpolater(df: np.ndarray): # 转换为DataFrame并修正字段类型 df = pd.DataFrame(df, columns=['MMSI', 'BaseDateTime', 'LAT', 'LON', 'SOG', 'COG']) df['BaseDateTime'] = df['BaseDateTime'].astype(float) df[['LAT', 'LON', 'SOG', 'COG']] = df[['LAT', 'LON', 'SOG', 'COG']].astype(float) interpolated_dfs = [] # 按MMSI分组处理单船数据 for mmsi, group in df.groupby('MMSI'): # 关键修改:计算累计时间戳(将相邻时间差转为实际时间点) group['cum_time'] = group['BaseDateTime'].cumsum() # 用累计时间戳作为索引,转为timedelta格式 group = group.set_index('cum_time') group.index = pd.to_timedelta(group.index, unit='s') # 按30秒间隔重采样,执行线性插值 resampled = group.resample('30S').interpolate(method='linear') # 恢复MMSI字段(resample会丢失分组标识) resampled['MMSI'] = mmsi # 重置索引,将累计时间转为秒数作为新的BaseDateTime resampled = resampled.reset_index() resampled['BaseDateTime'] = resampled['cum_time'].dt.total_seconds() # 保留目标输出列 resampled = resampled[['MMSI', 'BaseDateTime', 'LAT', 'LON', 'SOG', 'COG']] interpolated_dfs.append(resampled) # 合并所有分组结果并转为NumPy数组 interpolated_df = pd.concat(interpolated_dfs) return interpolated_df.to_numpy()
验证效果
修改后,MMSI=11的330秒处的LON值会是线性插值结果:-90.96787 + (-90.96793 - (-90.96787)) * (330 / 360) = -90.967925
其他字段也会按时间比例生成合理的插值结果,时间轴保持每30秒一条记录。
内容的提问来源于stack exchange,提问作者Andreas Ravnholt
相关产品推荐
相关产品推荐

