如何在 Pandas DataFrame 开头补全缺失时间戳并统一插值降频

本文介绍如何为不完整时间序列 dataframe 在起始端补全指定频率(如每分钟)的缺失时间戳,自动填充 nan 值,并支持后续线性插值与重采样,确保时间对齐分析的完整性与鲁棒性。

在处理从远程服务器(如空间物理观测平台 THEMIS/ARTEMIS)下载的时间序列数据时,常遇到一个典型问题:你指定了完整时间范围(例如 "2012-01-22/00:00:00" 到 "2012-01-23/23:59:59"),但实际返回的数据往往从中间某个时刻才开始(如 00:11:13),导致起始段缺失。原始数据本身不含“空档期”的时间戳,因此无法直接进行基于时间索引的插值或重采样(如 resample('1min').mean()),因为缺失时间点根本不在 DataFrame 中。

解决思路是:构造一个仅含目标起始时间到首个真实数据点之前、按所需频率(如 'min')生成的完整时间索引 DataFrame,所有数据列填充为 NaN,再将其与原始数据纵向拼接。关键在于保持列结构一致、时间列命名统一、索引逻辑清晰。

以下为推荐实现方式(兼容任意数量的数据列):

import pandas as pd
import numpy as np

# 假设 df_fgm 是你的原始 DataFrame,已设置 'Time' 为 datetime 类型列
# 示例中 df_fgm.columns = ['Time', 'BX_GSM', 'BY_GSM', 'BZ_GSM']

# 1.

定义期望的起始时间(用户指定) desired_start = pd.Timestamp("2012-01-22 00:00:00") # 2. 获取原始数据中第一个时间戳(注意:需确保 Time 列已转为 datetime) first_actual_time = df_fgm["Time"].iloc[0] # 3. 生成缺失时间段的分钟级时间索引(包含起始,不包含 first_actual_time 的前一分钟?→ 使用 closed='left' 更精确) # 注意:pd.date_range 默认 closed='both',若需严格补到 first_actual_time 的前一分钟(如 00:11:00),可调整 end 参数 missing_range = pd.date_range( start=desired_start, end=first_actual_time - pd.Timedelta("1s"), # 确保不重复包含首个真实时间点 freq='min', name='Time' ) # 4. 构造缺失部分 DataFrame:仅含 Time 列,其余列用 NaN 自动广播填充 # 方法一:使用 reindex(推荐,更显式且安全) missing_df = pd.DataFrame({'Time': missing_range}).reindex( columns=df_fgm.columns, # 严格对齐原始列名和顺序 fill_value=np.nan ) # 5. 拼接:缺失部分 + 原始数据 df_complete = pd.concat([missing_df, df_fgm], ignore_index=True) # 可选:按 Time 排序(若原始数据非严格升序,此步必要) df_complete = df_complete.sort_values('Time').reset_index(drop=True)

优势说明

  • reindex(columns=..., fill_value=np.nan) 确保所有原始数据列(无论多少个)均被正确创建并填充 NaN,无需硬编码列名;
  • 使用 pd.Timedelta("1s") 控制 end 边界,避免与首个真实时间点重复;
  • ignore_index=True 重置索引,保证连续整数索引;
  • sort_values('Time') 应对潜在乱序,提升鲁棒性。

完成补全后,即可无缝执行后续处理:

# 插值(线性)+ 重采样至 1 分钟均值
df_resampled = (df_complete
                .set_index('Time')
                .interpolate(method='linear')  # 沿时间轴插值 NaN
                .resample('1T')                 # '1T' 等价于 '1min'
                .mean()                         # 或 .first(), .last() 等
                .reset_index())

⚠️ 注意事项

  • 若原始数据存在末尾缺失,同理可构造 pd.date_range(start=last_actual_time + freq, end=desired_end, freq=freq) 并追加到底部;
  • interpolate() 默认按行(axis=0)插值,要求索引为 DatetimeIndex(故建议先 set_index('Time') 再插值);
  • 对高噪声数据,插值前可考虑先用 rolling(window='2T').mean() 平滑;
  • 若时间精度极高(如微秒级),确保 freq 参数与业务需求匹配('1T', '30S', '5T' 等)。

通过该方法,你将获得一个时间连续、结构完整、便于标准化分析的 DataFrame,为后续建模、可视化或特征工程奠定坚实基础。