解决Pandas中使用numpy.busday_count计算工作日数的类型报错
修复numpy.busday_count的TypeError问题
错误原因
np.busday_count要求输入的是天级别精度的日期数据(dtype('<M8[D]')),但你传入的是带时分秒的纳秒精度时间序列(dtype('<M8[ns]')),numpy的安全转换规则不允许自动截断时间部分,因此抛出类型错误。
解决方案
根据你的需求,分两种场景处理:
场景1:只统计完整的工作日天数(忽略时分秒)
将带时间的datetime转换为天级别精度即可,有两种常用方式:
- 使用
.dt.floor('D')截断到当天零点 - 使用
.dt.date转换为datetime.date对象
修改后的代码:
import numpy as np import pandas as pd # 补充缺失的pandas导入 pokus = {"start_date" : "2022-01-01 10:00:00" , "end_date" : "2022-01-01 17:00:00" } df = pd.DataFrame(pokus, index=[0]) # 转换为天级别精度的datetime start_dates = pd.to_datetime(df["start_date"]).dt.floor('D') end_dates = pd.to_datetime(df["end_date"]).dt.floor('D') # 计算工作日数 df["bus_days"] = np.busday_count(start_dates.values, end_dates.values)
注:如果起止日期是同一天,结果会是0,因为
busday_count统计的是结束日期之前的工作日数,不包含结束当天。
场景2:需要计算包含部分工作日的时长比例
如果要精确计算当天工作时长占一个工作日的比例(比如你的例子中7小时占8小时工作日的0.875),可以结合pandas的工作日偏移量和时长计算:
import pandas as pd import numpy as np from pandas.tseries.offsets import BDay pokus = {"start_date" : "2022-01-01 10:00:00" , "end_date" : "2022-01-01 17:00:00" } df = pd.DataFrame(pokus, index=[0]) # 转换为datetime类型 df['start_dt'] = pd.to_datetime(df['start_date']) df['end_dt'] = pd.to_datetime(df['end_date']) # 计算完整工作日天数 full_bus_days = np.busday_count(df['start_dt'].dt.floor('D').values, df['end_dt'].dt.floor('D').values) # 定义工作日的时间范围(这里假设是9:00-17:00,共8小时) workday_start = df['start_dt'].dt.floor('D') + pd.Timedelta(hours=9) workday_end = df['start_dt'].dt.floor('D') + pd.Timedelta(hours=17) # 截断起止时间到工作时间范围内 valid_start = df['start_dt'].clip(lower=workday_start, upper=workday_end) valid_end = df['end_dt'].clip(lower=workday_start, upper=workday_end) # 计算当天有效工作时长的比例 daily_fraction = (valid_end - valid_start).dt.total_seconds() / (8 * 3600) # 总工作日数 = 完整天数 + 当天比例(仅当天是工作日时生效) df['bus_days'] = full_bus_days + daily_fraction.where(np.is_busday(df['start_dt'].dt.date), 0)
注:可以根据实际的工作时间调整
workday_start和workday_end的设定。
内容的提问来源于stack exchange,提问作者vojtam
相关产品推荐
相关产品推荐

