看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在做时间数据的处理和分析时,不总是按照自然日去计算时间长度,有时需要考虑周末休假及法定调休中的上班的休假情况。本例假设某公司要分析项目的工作用时,以实际的工作日计算。
假设有以下数据:
import pandas as pd
# 构造测试数据
df = pd.DataFrame({
'项目':['a', 'b', 'c'],
'开始日期':['2020-04-28', '2020-07-09', '2021-01-15'],
'结束日期':['2020-05-15', '2020-08-10', '2021-01-22'],
})
df
'''
项目 开始日期 结束日期
0 a 2020-04-28 2020-05-15
1 b 2020-07-09 2020-08-10
2 c 2021-01-15 2021-01-22
'''
abc 三个项目,分别有项目的开始工作时间和结束工作时间,需要要计算它们按日作日实际的使用时长,天数。
我们小时候在计算时间时,会在日历上数日期,受此启发我们可以构造一个实际工作日的日历(时间序列),然后利用查询的方法将开始时间和结束时间传入,最终计算出有多少个日期。
至于真实工作日的计算实现方式,可以参考python工作日还是节假日判断 。需要把它的代码写成 workday.py
放到同目录的,导进来。(注意,不是用 pip 安装的哦)
最后再用 pandas 来增加列,得出结果。
# 自己写的判断工作日的方法
# 代码及逻辑见 https://gairuo.com/m/python-holiday
import workday
# 构造工作时间序列
df_work = (
pd.DataFrame(pd.date_range('20190101', '20210901'), columns=['day'])
.assign(workday=lambda x: x.day.apply(lambda d:workday.is_workday(d)))
.loc[lambda x: x.workday]
)
df_work
'''
day workday
1 2019-01-02 True
2 2019-01-03 True
3 2019-01-04 True
6 2019-01-07 True
7 2019-01-08 True
.. ... ...
968 2021-08-26 True
969 2021-08-27 True
972 2021-08-30 True
973 2021-08-31 True
974 2021-09-01 True
[656 rows x 2 columns]
'''
利用以上序列设计一个开始时间和结束时间之间工作日时长的计算函数:
# 计算两个日期间的工作日长度,传入工作时间序列计算
long = (lambda start, end:
df_work.loc[(df_work.day >= start) & (df_work.day <= end) ]
.count()
.day
)
# 实现矩阵运算
long_fun = lambda s,e: [long(s,e) for s,e in zip(s, e)]
# 测试
long('20200114', '20200120')
# 5
最终得到结果:
# 应用于计算
(
df.astype({'开始日期': 'datetime64[ns]',
'结束日期':'datetime64[ns]'}) # 转换为日期时间格式
.assign(项目天数=long_fun(df['开始日期'], df['结束日期']))
)
'''
项目 开始日期 结束日期 项目天数
0 a 2020-04-28 2020-05-15 12
1 b 2020-07-09 2020-08-10 23
2 c 2021-01-15 2021-01-22 6
'''
在定义 long 方法时,可以将时间设置为索引,然后用索引切片的方式使用:
# 构造工作时间序列
date_r = pd.date_range('20100101', '20220101')
df_work = (
pd.DataFrame(date_r, index=date_r, columns=['day'])
.agg({'day': lambda d:workday.is_workday(d)})
.loc[lambda x: x.day]
)
# 计算两个日期间的工作日长度,切片取索引,闭区间
long = lambda start, end: df_work.loc[start:end].count().day
# 实现矩阵运算
long_fun = lambda s,e: [long(s,e) for s,e in zip(s, e)]
上述改进会提升计算速度,但解释性不强。注:本改进对缺失开始时间和结束时间的会取之前全部或者之后全部,需要处理。
更新时间:2024-08-18 15:40:34 标签:pandas python 日期