为了提供一个更有启发性的示例,我创建了包含
多行的Schedule :
Start Date End Date Activity Type
0 2021-01-01 2021-05-31 10
1 2021-06-01 2021-12-31 20
我将假期创建为:
Holiday Start Date Holiday End Date
0 2021-02-14 2021-02-14
1 2021-03-10 2021-03-12
2 2021-07-04 2021-07-06
所有日期列都是datetime64类型。
一个准备步骤是从Holidays创建一个IntervalIndex:
ind = pd.IntervalIndex.from_arrays(Holidays['Holiday Start Date'],
Holidays['Holiday End Date'], closed='both')
要从单行获取结果,请创建以下函数:
def getActivities(row):
dd = pd.date_range(row['Start Date'], row['End Date'])
ss = dd.to_series().apply(lambda dat: ind.contains(dat).any())
s1 = ss[ss != ss.shift()]
s2 = ss[ss != ss.shift(-1)]
s1 = s1.astype(int) + row['Activity Type']
rv = s1.astype(int).reset_index().rename(columns={'index': 'Start Date',
0: 'Activity Type'})
rv.insert(1, 'End Date', s2.index)
return rv
要测试这个函数,你可以在一行上调用它,比如初始行:
getActivities(Schedule.iloc[0])
要完全了解所有详细信息,请在变量下保存一行Schedule :
row = Schedule.iloc[0]
然后执行getActivities中的每条指令并查看中间结果。
并且要获得所有行的预期结果,您必须将此函数的应用结果连接到每一行:
pd.concat(Schedule.apply(getActivities, axis=1).values, ignore_index=True)
对于我的测试数据,结果是:
Start Date End Date Activity Type
0 2021-01-01 2021-02-13 10
1 2021-02-14 2021-02-14 11
2 2021-02-15 2021-03-09 10
3 2021-03-10 2021-03-12 11
4 2021-03-13 2021-05-31 10
5 2021-06-01 2021-07-03 20
6 2021-07-04 2021-07-06 21
7 2021-07-07 2021-12-31 20
第 5 行来自Schedule的第0行,有 2 个假期。最后 3 行来自第1行,有 1 个假期。
请注意,Activity Type是原始值(对于“正常”期间)或原始值 + 1(对于假期期间),因此Schedule不应包含连续值作为Activity Type。