对无数据列的DataFrame执行rolling操作时的异常行为
Pandas rolling 聚合操作丢失time列的异常问题
先看正常场景的代码,能生成符合预期的结果:
import pandas as pd import numpy as np data = pd.DataFrame({'time': pd.date_range('2024-01-01 00:00', '2024-01-02 00:00', freq='1H'), 'data' : np.random.rand(25)}) # 正常返回包含time和data列的结果 data.rolling(window='3H', on='time').max()
但当移除唯一的数值列data后,执行相同的rolling+max操作:
# 仅保留time列的DataFrame执行rolling操作 data.drop(columns=['data']).rolling('3H', on='time').max()
程序既不报错也不提示警告,却返回一个只有索引、没有任何列的空DataFrame,导致后续依赖time列的处理流程直接失败。按预期,即便这个操作没有实际聚合意义,也应该返回输入的原DataFrame,而非丢失唯一的time列。
问题原因
Pandas的rolling聚合方法(比如max()、mean())只会对数值类型的列执行计算,而time列是datetime类型,不属于聚合目标范围。当DataFrame里没有数值列时,聚合操作找不到可处理的列,最终就返回了无列的空DataFrame。同时,on参数指定的time列只会作为rolling窗口的分组依据,不会自动被保留到结果中。
解决方案
可以通过提前判断或自定义逻辑来避免这个问题:
- 方案1:提前检查是否有数值列
在执行rolling操作前,先判断DataFrame里是否存在数值类型的列,没有则直接返回原数据:df = data.drop(columns=['data']) if np.any(df.dtypes == 'float64') or np.any(df.dtypes == 'int64'): result = df.rolling('3H', on='time').max() else: result = df.copy() - 方案2:强制保留time列
如果需要保留time列,哪怕聚合操作无意义,可以手动将time列转为数值类型(比如时间戳)参与聚合,之后再转回来:df = data.drop(columns=['data']).copy() df['time_ts'] = df['time'].astype('int64') result = df.rolling('3H', on='time').max().drop(columns=['time_ts']) # 恢复原time列 result['time'] = df['time'] - 方案3:自定义聚合函数
使用agg方法,指定对time列做恒等映射,确保列被保留:df = data.drop(columns=['data']) result = df.rolling('3H', on='time').agg({'time': lambda x: x.iloc[-1]})
内容的提问来源于stack exchange,提问作者Droid
相关产品推荐
相关产品推荐

