Python 使用另一个事件数据帧屏蔽日期数据帧
我有一个如下的数据帧Python 使用另一个事件数据帧屏蔽日期数据帧,python,pandas,Python,Pandas,我有一个如下的数据帧 df = pd.DataFrame({"date": pd.date_range(start="2012-03-01", end="2012-03-05"), "date+1": pd.date_range(start="2012-03-02", end="2012-03-06"),
df = pd.DataFrame({"date": pd.date_range(start="2012-03-01", end="2012-03-05"),
"date+1": pd.date_range(start="2012-03-02", end="2012-03-06"),
"date+2": pd.date_range(start="2012-03-03", end="2012-03-07")})
我还有另一个数据框,表示具有开始日期和结束日期的事件,如下所示
event = pd.DataFrame({"event": ["A", "B"],
"start": ["2012-03-02", "2012-03-04"],
"end": ["2012-03-03", "2012-03-06"]})
event["start"] = pd.to_datetime(event["start"])
event["end"] = pd.to_datetime(event["end"])
我想创建一个掩码数据框,如果df中的任何日期介于事件数据框中任何事件的开始日期和结束日期之间,则该掩码数据框将返回True。预期输出应为
0, 1, 1
1, 1, 1
1, 1, 1
1, 1, 1
1, 1, 0
该预期输出对应于df
2012-03-01, 2012-03-02, 2012-03-03
2012-03-02, 2012-03-03, 2012-03-04
2012-03-03, 2012-03-04, 2012-03-05
2012-03-04, 2012-03-05, 2012-03-06
2012-03-05, 2012-03-06, 2012-03-07
如您所见,只有2012-03-01和2012-03-07不在事件数据框中的任何事件之间。循环的计算代价可能很高。您能给我一些建议吗?您可以使用笛卡尔连接,然后检查日期是否介于间隔的开始和结束之间,并聚合:
# cartesian join
z = (df
.stack().reset_index().assign(k=1)
.merge(event.assign(k=1)))
# check if date between start and end
z['mask'] = z[0].between(z['start'], z['end'])
# aggregate
df_m = z.groupby(['level_0', 'level_1'])['mask'].max().unstack().astype(int)
df_m
输出:
level_1 date date+1 date+2
level_0
0 0 1 1
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 0
另外,如果您使用的是较新版本的
pandas
(1.2.0+),您可以直接使用merge(how='cross')
,而不是在合并前将k=1
分配给两个帧,然后检查日期是否在间隔的开始和结束之间,并聚合:
# cartesian join
z = (df
.stack().reset_index().assign(k=1)
.merge(event.assign(k=1)))
# check if date between start and end
z['mask'] = z[0].between(z['start'], z['end'])
# aggregate
df_m = z.groupby(['level_0', 'level_1'])['mask'].max().unstack().astype(int)
df_m
输出:
level_1 date date+1 date+2
level_0
0 0 1 1
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 0
另外,如果您使用的是较新版本的pandas
(1.2.0+),则可以使用merge(how='cross')
直接创建一个来自事件的<
intervals = pd.IntervalIndex.from_tuples([*zip(event.start, event.end)],
closed = 'both')
IntervalIndex([[2012-03-02, 2012-03-03], [2012-03-04, 2012-03-06]],
closed='both',
dtype='interval[datetime64[ns]]')
运行于df
:
df.applymap(lambda df: intervals.contains(df).any()).astype(int)
date date+1 date+2
0 0 1 1
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 0
从事件创建一个
intervals = pd.IntervalIndex.from_tuples([*zip(event.start, event.end)],
closed = 'both')
IntervalIndex([[2012-03-02, 2012-03-03], [2012-03-04, 2012-03-06]],
closed='both',
dtype='interval[datetime64[ns]]')
运行于df
:
df.applymap(lambda df: intervals.contains(df).any()).astype(int)
date date+1 date+2
0 0 1 1
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 0
使用datetime import timedelta中的如何?您可以使用诸如datetime('2012-03-01')+timedelta(days=1)
这只是一个示例。如果你愿意,我会给出完整的代码。我可以看看完整的代码吗?使用datetime import timedelta的怎么样?您可以使用诸如datetime('2012-03-01')+timedelta(days=1)
这只是一个示例。如果你愿意,我会给出完整的代码。我可以看看完整的代码吗?