如何高效计算DataFrame多日期列间的工作日天数(适配多列场景)
问题:高效计算DataFrame多日期列间的工作日天数
我有一个包含4列日期数据的DataFrame,具体数据如下:
col1 col2 col3 col4 0 2021-10-18 2021-10-27 2021-11-08 2021-11-21 1 2021-01-30 2021-02-01 2021-02-28 2021-03-18 2 2021-08-17 2021-08-20 2021-09-02 2021-09-07
我希望计算这些日期列之间的工作日天数,目前已实现的代码如下:
col1 = [d.date() for d in df['col1']] col2 = [d.date() for d in df['col2 ']] col3 = [d.date() for d in df['col3']] col4 = [d.date() for d in df['col4 ']] df['bday1'] = np.busday_count(col1, col2) df['bday2'] = np.busday_count(col2, col3) df['bday3'] = np.busday_count(col3, col4)
请问是否存在更高效的实现方式?尤其是当DataFrame包含更多日期列时,该如何优化这一计算过程?
优化方案
当然有更高效的方式!你的当前代码需要手动逐个处理列,当日期列数量增多时会非常繁琐,而且重复的列表推导也不够优雅。这里有几个实用的优化思路:
1. 先统一转换日期格式,省去重复类型转换
首先确保你的日期列已经是datetime64类型(如果还不是,先运行df = df.apply(pd.to_datetime))。numpy.busday_count其实可以直接接收pandas的Series(只要是datetime类型),完全不需要手动转成date()对象的列表,这一步能省去大量重复代码:
import numpy as np import pandas as pd # 确保日期列是datetime类型 df = df.apply(pd.to_datetime) # 直接用Series计算,无需手动转列表 df['bday1'] = np.busday_count(df['col1'], df['col2']) df['bday2'] = np.busday_count(df['col2'], df['col3']) df['bday3'] = np.busday_count(df['col3'], df['col4'])
2. 用循环批量处理,适配任意数量的日期列
如果你的DataFrame有N个日期列(比如col1到coln),可以通过循环遍历相邻列对来自动生成工作日差列,完全不用手动写每一行:
# 获取所有日期列的名称(如果日期列不连续,可手动指定列名列表) date_cols = df.columns.tolist() # 遍历相邻的列对 for i in range(len(date_cols)-1): col_start = date_cols[i] col_end = date_cols[i+1] # 生成直观的新列名 new_col_name = f'bday_{col_start}_to_{col_end}' df[new_col_name] = np.busday_count(df[col_start], df[col_end])
这样不管你有5列还是20列日期数据,都能一键生成所有相邻列的工作日差,代码复用性拉满。
3. 利用pandas的shift做向量化运算,适配超大数据集
如果你的数据集非常大,Python层面的循环可能会影响性能,这时可以用shift方法把日期列对齐,再做全量向量化计算:
# 生成"下一列"的日期数据(去掉第一列) next_date_df = df.shift(axis=1).iloc[:, 1:] # 全量计算工作日差 bday_diff_values = np.busday_count(df.values, next_date_df.values) # 把结果转成DataFrame并合并到原df bday_diff_df = pd.DataFrame( bday_diff_values, columns=[f'bday{i+1}' for i in range(len(df.columns)-1)] ) df = pd.concat([df, bday_diff_df], axis=1)
这种方法完全依赖numpy的底层运算,避免了Python循环的开销,在处理百万级行数据时性能优势会很明显。
额外提示
- 如果需要排除自定义节假日,可以给
np.busday_count传入holidays参数,比如np.busday_count(start, end, holidays=custom_holidays),其中custom_holidays是一个datetime对象的数组。 - 一定要确保所有日期列的类型是
datetime64[ns],字符串类型直接传入会报错。
内容的提问来源于stack exchange,提问作者bella
相关产品推荐
相关产品推荐

