基于另一列条件优化np.busday_count:用向量化替代循环
嘿,这个问题我之前踩过坑!np.busday_count默认的“对齐非工作日到最近工作日”的逻辑确实会和你的需求冲突——就像你说的,周六到周二它算1个工作日,但你实际想要的是2天(周一+周二)。
完全不用靠慢到离谱的for循环或者.apply,用numpy的向量化操作就能高效解决,而且速度快到飞起。下面是具体的实现思路和代码:
核心思路
np.busday_count之所以会少算一天,是因为它会把周六/周日的起始日期自动调整到下一个周一,然后按左闭右开的规则计算工作日。我们只需要给所有起始日期是周末且起始早于结束的情况,在原始计数基础上加1就行——这一步用numpy的数组掩码就能批量完成,完全不用逐行遍历。
具体代码实现
纯numpy版本
import numpy as np # 示例日期数组 start_dates = np.array(['2024-05-18', '2024-05-20', '2024-05-19'], dtype='datetime64[D]') # 周六、周一、周日 end_dates = np.array(['2024-05-21', '2024-05-21', '2024-05-22'], dtype='datetime64[D]') # 周二、周二、周三 # 计算原始工作日数 base_count = np.busday_count(start_dates, end_dates) # 获取起始日期的星期几(0=周一,5=周六,6=周日) start_weekday = start_dates.view('int64') % 7 # 创建掩码:标记起始是周末且起始日期早于结束日期的情况 weekend_start_mask = (start_weekday >= 5) & (start_dates < end_dates) # 调整计数 adjusted_count = base_count.copy() adjusted_count[weekend_start_mask] += 1 print("原始计数:", base_count) # 输出 [1 1 1] print("调整后计数:", adjusted_count) # 输出 [2 1 2],完全符合你的预期
Pandas版本(如果用DataFrame处理数据)
import pandas as pd import numpy as np df = pd.DataFrame({ 'start': pd.to_datetime(['2024-05-18', '2024-05-20', '2024-05-19']), 'end': pd.to_datetime(['2024-05-21', '2024-05-21', '2024-05-22']) }) # 计算原始工作日数 df['base_count'] = np.busday_count(df['start'].values, df['end'].values) # 生成调整值:符合条件的加1,否则加0 df['adjustment'] = ((df['start'].dt.weekday >= 5) & (df['start'] < df['end'])).astype(int) # 得到最终结果 df['adjusted_count'] = df['base_count'] + df['adjustment'] print(df)
为什么这个方法快?
numpy的数组操作是基于C语言实现的批量计算,不需要像for循环或者.apply那样逐行处理每一个元素——哪怕你的数据有几十万行,这个操作也能在瞬间完成。
内容的提问来源于stack exchange,提问作者Leon Kyriacou
相关产品推荐
相关产品推荐

