Pandas 的 resample().ffill() 在将日频数据升频为小时频时,会因时间范围截断导致末尾日期的 23 小时缺失;根本原因是重采样默认以左闭右开区间划分桶,最后一个日期仅生成一个时间戳(当日 00:00),需通过扩展索引边界并清理冗余项来完整覆盖全部 24 小时。
pandas 的 `resample().ffill()` 在将日频数据升频为小时频时,会因时间范围截断导致末尾日期的 23 小时缺失;根本原因是重采样默认以左闭右开区间划分桶,最后一个日期仅生成一个时间戳(当日 00:00),需通过扩展索引边界并清理冗余项来完整覆盖全部 24 小时。
在使用 Pandas 对时间序列进行升频(upsampling)操作时,resample("h").ffill() 是常见做法:它将每个日度观测值向前填充至对应日内的所有小时点。但实践中常遇到一个隐蔽问题——最后一个日期只生成 1 行(如 2024-01-02 00:00),而非预期的 24 行(2024-01-02 00:00 至 2024-01-02 23:00),导致最终结果长度异常(例如 2 天本应得 48 行,却只返回 25 行)。
问题根源:Resample 的区间规则
Pandas 的 resample(freq="h") 默认按 左闭右开(left-inclusive, right-exclusive) 规则对时间索引分桶。当原始数据最后一天为 2024-01-02(无时分秒,默认为 00:00:00),重采样器将其视为一个精确的时间点,并仅分配到 [2024-01-02 00:00, 2024-01-02 01:00) 这个桶中,因此只生成该时刻一行,后续小时无数据可填充。
解决方案:主动延伸时间边界
标准做法是在原始数据末尾添加一个占位日期(+1 天)并赋 NaN 值,确保重采样器能自然延伸出完整的最后一日 24 小时桶,再通过 dropna() 清理掉新增的无效行:
import pandas as pd
T1 = pd.Timestamp("2024-01-01")
T2 = pd.Timestamp("2024-01-02")
T3 = pd.Timestamp("2024-01-03") # 占位日期:确保覆盖 T2 全天
df = pd.DataFrame({
"T": [T1, T2, T3],
"V": [1, 2, pd.NA] # NA 确保不干扰前向填充
})
result = (df
.set_index("T")
.resample("h")
.ffill()
.dropna(subset=["V"]) # 更安全:仅按目标列过滤
)
print(f"Shape: {result.shape}") # 输出: (48, 1)
print(result.index[:3].tolist()) # [Timestamp('2024-01-01 00:00:00'), ...]
print(result.index[-3:].tolist()) # [..., Timestamp('2024-01-02 21:00:00'), '22:00', '23:00']
注意事项与最佳实践
- ✅ 始终用 dropna(subset=[col]) 替代无参数 dropna():避免意外删除其他合法空列;
- ✅ 若原始数据含多列,建议在 ffill() 后用 bfill() 或 limit=23 控制填充深度,防止跨日污染;
- ⚠️ 避免依赖 closed/label 参数强行调整(如 closed="right"),因其可能引发时区或边界歧义,且不解决根本逻辑;
- ? 若处理带时区数据(如 tz_localize),务必确保占位日期与原始时区一致,否则 resample 可能报错或产生偏移;
- ? 批量处理时,可封装为函数:
def daily_to_hourly(df, date_col, value_col):
df = df.sort_values(date_col).copy()
last_date = df[date_col].max()
next_date = last_date + pd.Timedelta(days=1)
df_ext = pd.concat([
df,
pd.DataFrame({date_col: [next_date], value_col: [pd.NA]})
], ignore_index=True)
return (df_ext
.set_index(date_col)
.resample("h")
.ffill()
.dropna(subset=[value_col]))
# 使用示例
hourly_df = daily_to_hourly(df, "T", "V")
该方法稳定、可复现,适用于任意长度的日频时间序列,是 Pandas 升频场景下的推荐工程实践。











