如何高效对含毫秒级时间戳的Pandas DataFrame重采样与插值?
问题
我有一个包含毫秒精度timestamp和对应altitude值的Pandas DataFrame,想要高效完成重采样与插值操作。以下是示例数据生成代码:
import pandas as pd import numpy as np # 生成同一分钟内的5个带毫秒精度的随机时间戳 base_timestamp = pd.Timestamp.now().floor("min") # 获取当前时间,向下取整到最近分钟 timestamps = [ base_timestamp + pd.to_timedelta(np.random.randint(0, 60000), unit="ms") for _ in range(5) ] # 生成随机海拔值 altitudes = np.random.uniform(100, 1000, size=5) # 100到1000之间的随机海拔 # 创建DataFrame并按时间戳排序 df = pd.DataFrame({"timestamp": timestamps, "altitude": altitudes}).sort_values("timestamp")
我目前用的方法可行但效率极低:
df_interpolated = ( df.set_index("timestamp").resample("1ms").interpolate().resample("1s").interpolate() )
通过绘图可验证该方法有效:
import plotly.graph_objects as go fig = go.Figure() fig.add_trace(go.Scatter(x=df.timestamp, y=df.altitude, mode="lines", name="Original")) fig.add_trace( go.Scatter( x=df_interpolated.index, y=df_interpolated.altitude, mode="markers", name="Interpolated 1ms and 1s", ) ) fig.show()

请问有什么更高效的实现方案?
高效实现方案
核心优化思路
原方法效率低的根本原因是先生成了百万级的1ms采样点(每分钟60000行),再降采样到1s,完全做了无用功。直接生成目标的1s采样序列,再针对该序列插值即可,能大幅减少计算量。
方案1:直接生成1s时间序列并插值
# 设置时间索引 df_indexed = df.set_index("timestamp") # 生成目标1s采样的时间序列:从数据起始到结束,步长1s start_time = df_indexed.index.min().floor("s") end_time = df_indexed.index.max().ceil("s") target_times = pd.date_range(start=start_time, end=end_time, freq="1s") # 重索引到目标时间序列并插值(默认线性插值,可指定method参数) df_interpolated = df_indexed.reindex(target_times).interpolate(method="linear")
方案2:用resample直接生成目标采样并插值
也可以直接用resample指定目标频率,结合interpolate一步完成,避免中间的1ms采样步骤:
df_interpolated = df.set_index("timestamp").resample("1s").interpolate(method="linear")
额外优化建议
如果数据量极大,可考虑使用scipy.interpolate中的插值函数(如interp1d),将时间戳转换为数值(如Unix时间戳)后进行插值,速度会更快:
from scipy.interpolate import interp1d # 将时间戳转换为Unix毫秒数 x = df["timestamp"].astype(np.int64) // 10**6 y = df["altitude"] # 创建插值函数 f = interp1d(x, y, kind="linear", fill_value="extrapolate") # 生成目标1s时间序列的Unix毫秒数 target_times = pd.date_range(start=df["timestamp"].min().floor("s"), end=df["timestamp"].max().ceil("s"), freq="1s") target_x = target_times.astype(np.int64) // 10**6 # 计算插值结果 interpolated_y = f(target_x) # 转换回DataFrame df_interpolated = pd.DataFrame({"altitude": interpolated_y}, index=target_times)
效果验证
上述优化方法的结果和原方法完全一致,但计算效率提升数十倍甚至上百倍,尤其是当时间范围较长时,差异会更明显。
内容的提问来源于stack exchange,提问作者bfgt
相关产品推荐
相关产品推荐

