Pandas日期做差筛选超30天账户数据报TypeError如何解决
问题说明
现有如下结构的DataFrame df1:
Acc_id Acc_name Acc_end_date qqq-1 test1 12/31/2021 www-2 test2 05/28/2022 yyy-6 test3 06/15/2022 zzz-6 test4 06/17/2022 kkk-6 test5 03/16/2022
其中Acc_end_date字段存储日期值,需求为筛选出截止今日,Acc_end_date对应日期已过去30天以上的账户ID。
原有实现代码触发两类报错:
- 第一版代码报错:
TypeError: unsupported operand type(s) for -: 'DatetimeArray' and 'list' - 调整后代码报错:
TypeError: unsupported operand type(s) for -: 'DatetimeArray' and 'datetime.date'
报错根因
- 第一版错误:代码中
np.array(todays_date)没有将转换结果赋值回原变量,实际参与运算的还是Python原生列表,pandas的DatetimeArray不支持直接和list做减法运算;且循环生成重复日期列表的写法完全冗余,pandas原生支持标量广播运算,不需要手动构造等长数组。 - 第二版错误:
pd.to_datetime转换后的列是datetime64[ns]时间戳类型,而date.today()返回的是Python原生date对象,二者精度、类型均不匹配,无法直接运算;同时代码中引用了未定义的only_inactive变量,也会触发额外错误。 - 逻辑错误:原有代码写反了日期运算的减数、被减数顺序,且日期做差得到的是Timedelta类型,直接和整数30比较存在类型兼容问题,就算类型匹配也会得到全为False的筛选结果。
正确实现
不需要循环构造日期数组,直接使用pandas兼容的时间类型做运算即可,完整代码如下:
import pandas as pd # 转换列为datetime类型,显式指定日期格式避免解析错误,如果是两位年份把%Y改成%y即可 df1['Acc_end_date'] = pd.to_datetime(df1['Acc_end_date'], format='%m/%d/%Y') # 获取和列类型兼容的当日日期,normalize()将时间重置为当日0点,避免时分秒带来的计算误差 today = pd.Timestamp.today().normalize() # 计算日期间隔天数,筛选已过期超过30天的记录 df2 = df1[(today - df1['Acc_end_date']).dt.days > 30]
关键注意点:
- 调用
pd.to_datetime时显式传入format参数,既可以避免pandas自动解析时出现月、日颠倒的错误,也能大幅提升大数据集下的转换效率。 - 用
pd.Timestamp.today()替代原生date.today(),返回值类型和DataFrame中datetime列完全匹配,不需要额外做类型转换。 - 日期做差后通过
.dt.days取出间隔的天数值,再和30做数值比较,规避Timedelta类型和整数直接比较的兼容问题。 - 运算顺序为「今日日期 - 账户结束日期」,得到的是账户结束日期距离今日过去的天数,符合筛选逻辑。
内容的提问来源于stack exchange,提问作者user13024918
相关产品推荐
相关产品推荐

