首页 > 解决方案 > 在下一个事件开始时计算已完成的事件

问题描述

我有一个数据集,可以测量多个人(id)持续多天的事件(event_start 到 event_end)。我想在下一个事件的日期计算已完成事件的数量。我可以通过 iterrows 做到这一点,但这在规模上非常缓慢。你能帮我减少运行时间吗?

df = pd.DataFrame([{'id': 1, 'event_start': '2020-01-01', 'event_end': '2020-01-03'},
{'id': 1, 'event_start': '2020-01-02', 'event_end': '2020-01-04'},
{'id': 1, 'event_start': '2020-01-03', 'event_end': '2020-01-05'},
{'id': 1, 'event_start': '2020-01-07', 'event_end': '2020-01-10'},
{'id': 2, 'event_start': '2020-01-06', 'event_end': '2020-01-07'},
{'id': 2, 'event_start': '2020-01-08', 'event_end': '2020-01-10'},])
df['event_start'] = pd.to_datetime(df['event_start'])
df['event_end'] = pd.to_datetime(df['event_end'])
df = df.sort_values(['id', 'event_start', 'event_end'])

for index, row in df.iterrows():
   df.at[index, 'Previous Count'] = df[(df['id'] == row['id']) & (df['event_end'] < row['event_start'])].count()[0]

df

标签: pythonpandasdataframevectorization

解决方案


我比较了这两种策略

首先是你的

%time
df = pd.DataFrame([{'id': 1, 'event_start': '2020-01-01', 'event_end': '2020-01-03'},
{'id': 1, 'event_start': '2020-01-02', 'event_end': '2020-01-04'},
{'id': 1, 'event_start': '2020-01-03', 'event_end': '2020-01-05'},
{'id': 1, 'event_start': '2020-01-07', 'event_end': '2020-01-10'},
{'id': 2, 'event_start': '2020-01-06', 'event_end': '2020-01-07'},
{'id': 2, 'event_start': '2020-01-08', 'event_end': '2020-01-10'},])
df['event_start'] = pd.to_datetime(df['event_start'])
df['event_end'] = pd.to_datetime(df['event_end'])
df = df.sort_values(['id', 'event_start', 'event_end'])

for index, row in df.iterrows():
   df.at[index, 'Previous Count'] = df[(df['id'] == row['id']) & (df['event_end'] < row['event_start'])].count()[0]

df

我得到了

CPU times: user 2 µs, sys: 0 ns, total: 2 µs
Wall time: 5.01 µs

然后我尝试使用 groupby 将 iterrows 减少到同一个 ID。我不确定这是否会更快,除非数据帧很大,因为设置时间会更长。

%time
df = pd.DataFrame([{'id': 1, 'event_start': '2020-01-01', 'event_end': '2020-01-03'},
{'id': 1, 'event_start': '2020-01-02', 'event_end': '2020-01-04'},
{'id': 1, 'event_start': '2020-01-03', 'event_end': '2020-01-05'},
{'id': 1, 'event_start': '2020-01-07', 'event_end': '2020-01-10'},
{'id': 2, 'event_start': '2020-01-06', 'event_end': '2020-01-07'},
{'id': 2, 'event_start': '2020-01-08', 'event_end': '2020-01-10'},])
df['event_start'] = pd.to_datetime(df['event_start'])
df['event_end'] = pd.to_datetime(df['event_end'])
df = df.sort_values(['id', 'event_start', 'event_end'])

outdf = pd.DataFrame(columns=df.columns)
for id, subdf in df.groupby('id'):
    for index, row in subdf.iterrows():
        subdf.at[index, 'Previous Count'] = subdf[(subdf['event_end'] < row['event_start'])].count()[0]
    outdf = pd.concat([outdf,subdf])

outdf

我得到了

CPU times: user 2 µs, sys: 1 µs, total: 3 µs
Wall time: 5.96 µs

您的里程将根据您的大数据框的大小和组成而有所不同,但值得一试。


推荐阅读