如何在不填充缺失时段的情况下重采样Pandas DataFrame?
如何在Pandas重采样稀疏时间序列时避免生成全NaN行?
你提到的问题确实很常见——当处理跨度大且稀疏的时间序列时,用resample会生成大量无意义的全NaN行,既浪费内存又拖慢计算。虽然dropna(how="all")能解决结果问题,但先创建再删除的方式不够高效,也不够严谨。
这里有个更优的方案:直接按目标时间粒度分组计算,而不是用resample生成所有时间点。
方法一:按日期分组(针对日粒度重采样)
对于你的示例,要计算日平均值,我们可以直接提取索引的日期部分作为分组键,再计算均值:
import numpy as np import pandas as pd # 构造你的示例数据 freq1 = pd.date_range("20000101", periods=10, freq="S") freq2 = pd.date_range("20200101", periods=10, freq="S") index = np.hstack([freq1.values, freq2.values]) data = np.random.randint(0, 100, (20, 10)) cols = list("ABCDEFGHIJ") df = pd.DataFrame(index=index, data=data, columns=cols) # 按日期分组计算日平均,直接得到有数据的日期结果 df_daily = df.groupby(df.index.date).mean() # 如果需要将索引转回DatetimeIndex(默认是object类型的日期对象) df_daily.index = pd.to_datetime(df_daily.index)
这个方法的核心是:groupby只会基于实际存在数据的日期创建分组,不会填充两个时间区间之间的空白日期,所以结果里只会有2000-01-01和2020-01-01两行,完全没有全NaN行。
方法二:灵活适配其他时间粒度(月度/季度等)
如果需要其他时间粒度的重采样,比如月度平均,可以用to_period()方法将索引转换为对应周期,再分组:
# 月度平均,仅保留有数据的月份 df_monthly = df.groupby(df.index.to_period('M')).mean() # 可选:将周期索引转回时间戳(比如转为每月最后一天) df_monthly.index = df_monthly.index.to_timestamp('M')
为什么这比resample+dropna更好?
- 性能更优:
resample会先生成从最早到最晚日期之间的所有时间点(你的示例里是7305天),哪怕这些时间点没有任何数据;而分组方法直接跳过空白区间,只处理有数据的时间粒度,内存占用和计算时间都会大幅降低。 - 逻辑更严谨:不需要先创建无用数据再删除,从根源上避免了全NaN行的生成。
补充:如果一定要用resample怎么办?
如果因为某些场景必须用resample(比如需要统一的时间序列索引做后续对齐),可以在resample时结合closed、label等参数,但最终还是需要dropna。不过对于稀疏数据,还是优先推荐分组的方式。
内容的提问来源于stack exchange,提问作者tnknepp
相关产品推荐
相关产品推荐

