【发布时间】:2020-07-07 05:36:49
【问题描述】:
我正在分析一组事件,每个事件都有一个类型、开始和结束时间戳。 我正在尝试总结在该时间范围内正在进行的每个事件时间的并发数。
考虑下面的数据集,列出事件 N1-N4,每个事件都有重叠范围:
>>> data = {
... 'name' : [ 'N1', 'N2', 'N3', 'N4', 'N1', 'N2', 'N7'],
... 'start_dt_str' : ['01-01-2020', '01-03-2020', '01-01-2020', '01-01-2020', '01-03-2020', '01-04-2020','01-10-2020'],
... 'end_dt_str' : ['01-03-2020', '01-05-2020', '01-05-2020', '01-02-2020', '01-04-2020', '01-05-2020', '01-11-2020']
... }
>>> df = pd.DataFrame(data)
>>> df['start_dt'] = pd.to_datetime(df['start_dt_str'])
>>> df['end_dt'] = pd.to_datetime(df['end_dt_str'])
>>> del df['start_dt_str']
>>> del df['end_dt_str']
>>> df
name start_dt end_dt
0 N1 2020-01-01 2020-01-03
1 N2 2020-01-03 2020-01-05
2 N3 2020-01-01 2020-01-05
3 N4 2020-01-01 2020-01-02
4 N1 2020-01-03 2020-01-04
5 N2 2020-01-04 2020-01-05
6 N7 2020-01-10 2020-01-11
我的目标是生成此摘要,即范围内每个日期的并发事件数(按类型)。这将是正确的答案:
N1 N2 N3 N4 N7
2020-01-01 1 0 1 1 0
2020-01-02 1 0 1 1 0
2020-01-03 2 1 1 0 0
2020-01-04 1 2 1 0 0
2020-01-05 1 2 0 0 0
2020-01-06 0 0 0 0 0
2020-01-07 0 0 0 0 0
2020-01-08 0 0 0 0 0
2020-01-09 0 0 0 0 0
2020-01-10 0 0 0 0 1
2020-01-11 0 0 0 0 1
请注意,start_dt 和 end_dt 列中都有重复的日期。
另请注意,该解决方案必须能够对数据重新采样,以便用包含全零的行填充缺失的日期。在此示例中,日期 01-09 不会显示为开始日期或结束日期,但必须出现在输出中。在一般情况下,我希望能够进行重新采样以选择任意间隔。
为简单说明问题,上述数据集中的报告期和数据均采用天精度。在实际数据集中,start_dt 和 end_dt 是毫秒级精度(但仍然包含重复),报告周期可以是小时、天、周等。
另请注意,数据中存在差距,因此需要重新采样以生成日期时间序列。 (即,即使数据是毫秒精度,也有一整天的缺失)。
我尝试了几种不起作用的方法。首先,这似乎很简单,我尝试了:
df.set_index(['name','start_dt']).groupby('name').resample('D',level='start_dt').ffill()
ValueError: Upsampling from level= or on= selection is not supported, use .set_index(...) to explicitly set index to datetime-like
这导致this pandas issue 关于上采样是开放的,并提供了一些解决方法。不幸的是,我们不能只使用 start_dt(或 end_dt)作为索引,因为它是非唯一的:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/resample.py", line 453, in pad
return self._upsample("pad", limit=limit)
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/resample.py", line 1095, in _upsample
res_index, method=method, limit=limit, fill_value=fill_value
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/util/_decorators.py", line 227, in wrapper
return func(*args, **kwargs)
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/frame.py", line 3856, in reindex
return super().reindex(**kwargs)
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/generic.py", line 4544, in reindex
axes, level, limit, tolerance, method, fill_value, copy
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/frame.py", line 3744, in _reindex_axes
index, method, copy, level, fill_value, limit, tolerance
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/frame.py", line 3760, in _reindex_index
new_index, method=method, level=level, limit=limit, tolerance=tolerance
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/indexes/base.py", line 3149, in reindex
"cannot reindex a non-unique index "
ValueError: cannot reindex a non-unique index with a method or limit
This question 这似乎与我的问题相似,但并未填写每种事件类型范围内的所有日期:
>>> df.set_index('start_dt').groupby('name').resample('D').asfreq()
name end_dt
name start_dt
N1 2020-01-01 N1 2020-01-03
2020-01-02 NaN NaT
2020-01-03 N1 2020-01-04
N2 2020-01-03 N2 2020-01-05
2020-01-04 N2 2020-01-05
N3 2020-01-01 N3 2020-01-05
N4 2020-01-01 N4 2020-01-02
This solution 看起来很有希望,但也不是我所需要的。它本质上是在一个范围内查找单个事件,但不计算正在进行的总数。虽然使用 IntervalIndex 似乎是一个好的开始。
我觉得这应该很容易,但显然我的 pandas foo 严重不足。
非常感谢您的帮助!
编辑:
【问题讨论】: