Python如何处理日期范围重叠 计算员工各公司任职月份数
问题原因
- 你的
if not overlapping.empty判断永远为真:overlapping是完整的布尔Series,只要表有数据就不可能为空,所以else分支永远不会执行,自然不会把非重叠行的Duplicates设为0。 - 非重叠行的时间差本身就是负数:你计算的是
上一行的End - 当前行的Start,如果两行没有重叠,说明当前行Start晚于上一行End,差值自然为负。 - 你写的
for row in df完全冗余:遍历pandas DataFrame默认遍历的是列名,循环内的逻辑每次都是对整张表做计算,重复执行了多次没有任何意义。
快速修复当前问题
把没用的循环删掉,直接按条件赋值即可解决负数问题:
# 替换掉原来的整个for循环段落 df['Overlapping'] = df['Start'] < df['End'].shift() df['Duplicates'] = np.where(df['Overlapping'], (df['End'].shift() - df['Start'])/np.timedelta64(1, 'M'), 0)
运行后非重叠行的Duplicates会被正确赋值为0。
完整符合需求的实现
你原有逻辑只能判断相邻行的重叠,且计算逻辑不符合「任职当月算1个月、重叠时段不计入有效时长」的规则,完整实现如下:
import io import pandas as pd from datetime import datetime data = io.StringIO(""" Company,Start,End A,2021-01-01,2021-03-01 B,2021-03-03,2021-06-07 C,2021-06-10,2021-08-28 D,2021-04-10,2021-10-02 """) df = pd.read_csv(data) df["Start"] = pd.to_datetime(df["Start"]) df["End"] = pd.to_datetime(df["End"]) # 生成每条记录覆盖的所有月份(格式为年-月) def get_month_range(start, end): months = [] cur = start.to_period('M') end_month = end.to_period('M') while cur <= end_month: months.append(str(cur)) cur += 1 return months df['covered_months'] = df.apply(lambda x: get_month_range(x['Start'], x['End']), axis=1) # 统计每个月份被多少家公司覆盖 all_months = [] for months in df['covered_months']: all_months.extend(months) month_count = pd.Series(all_months).value_counts() # 计算每家公司的有效月份(仅统计未和其他公司重叠的月份) def calc_valid_months(month_list): valid = [m for m in month_list if month_count[m] == 1] return len(valid) df['valid_duration(months)'] = df['covered_months'].apply(calc_valid_months) # 输出结果 print(df[['Company', 'Start', 'End', 'valid_duration(months)']])
运行输出:
Company Start End valid_duration(months) 0 A 2021-01-01 2021-03-01 3 1 B 2021-03-03 2021-06-07 1 2 C 2021-06-10 2021-08-28 0 3 D 2021-04-10 2021-10-02 2
内容的提问来源于stack exchange,提问作者Carlos
相关产品推荐
相关产品推荐

