Pandas计算日期间隔天数 报&运算符不支持DatetimeArray类型错误
报错产生原因
- 运算符优先级错误:Python中按位与运算符
&的优先级高于比较运算符<=/>=/</>,原代码里写的datedebut<=d0 & datefin>=d0会被解析为datedebut <= (d0 & datefin) >= d0,而pandas的DatetimeArray类型不支持直接做&按位与运算,直接触发类型报错。 - 函数传参逻辑错误:原函数是针对单个日期标量写的分支判断,直接把整列Series作为参数传入时,if/elif分支无法对整列数组做逐元素判断,就算修好运算符问题也无法得到正确结果。
- 逻辑边界缺失:原函数没有覆盖「用户日期区间和2021年10月完全不重叠」的场景,这类行计算时会返回空值。
- 日期解析风险:原代码调用
pd.to_datetime时没有指定dayfirst=True,"01/10/2021"这类日/月/年格式的字符串会被默认解析为1月10日,而非预期的10月1日,会导致后续计算结果完全错误。
代码修正方案
优先用pandas向量化逻辑实现,不需要写多分支判断,性能远高于逐行apply,核心是用日期区间重叠的通用公式:重叠天数 = 两个区间的较晚开始日期 到 两个区间的较早结束日期 的间隔天数,无重叠则返回0。
完整可运行代码如下:
import pandas as pd # 统一解析所有日期列,指定dayfirst=True适配日/月/年格式 df["mois0"] = pd.to_datetime("01/10/2021", dayfirst=True) df["mois1"] = pd.to_datetime("31/10/2021", dayfirst=True) df["De"] = pd.to_datetime(df["De"], dayfirst=True) df["-"] = pd.to_datetime(df["-"], dayfirst=True) # 计算重叠区间的起止时间 overlap_start = df[["De", "mois0"]].max(axis=1) overlap_end = df[["-", "mois1"]].min(axis=1) # 计算天数,无重叠的情况赋值为0 df["abs_202110"] = (overlap_end - overlap_start).dt.days + 1 df.loc[df["abs_202110"] < 0, "abs_202110"] = 0
如果需要保留原有自定义函数的写法,需要修正运算符、补全边界,同时用apply逐行传入标量值:
def calculAbsMois(datedebut, datefin, d0, d1): # 补全无重叠的边界场景 if datefin < d0 or datedebut > d1: return 0 # 比较条件加括号,标量逻辑判断用and而非& if (datedebut <= d0) and (datefin >= d0): if datefin > d1: return (d1 - d0).days + 1 else: return (datefin - d0).days + 1 elif (datedebut < d1) and (datefin > d1): return (d1 - datedebut).days + 1 elif (datedebut >= d0) and (datefin <= d1): return (datefin - datedebut).days + 1 # 逐行调用函数传入标量参数 df['abs_202110'] = df.apply( lambda row: calculAbsMois(row["De"], row["-"], row["mois0"], row["mois1"]), axis=1 )
补充说明:如果是对整列做布尔逻辑筛选,pandas中需要用&且每个比较条件必须加括号,比如(df['a'] > 1) & (df['b'] < 2),但普通Python标量值的逻辑判断要使用and/or/not,不要和数组级的按位逻辑运算符混用。
内容的提问来源于stack exchange,提问作者Nat Parsy
相关产品推荐
相关产品推荐

