我有一个数据框,其中每一行都有开始时间和结束时间。每行也有一个他们所属的组。我想要一个新列,以秒为单位给出该组中所有时间的总和。
例如,如果我们有一个如下所示的组:
id1: |----|
id2: |-----|
id3: |--------|
. . . . . . . . . . .
time -> 12:00 12:04 12:07 12:10
然后对于属于该组的所有行将获得 4+3 分钟 = 420 秒的总时间
如果它们完全重叠,那么我们会得到这样的场景:
id1: |--------|
id2: |--------|
. . . . . . . . . . .
time -> 12:00 12:04 12:07 12:10
这将为我们提供 4 分钟 = 240 秒的结果。
下面是一些虚拟数据:
import pandas as pd
ids = [x for x in range(10)]
group = [0, 1, 1, 2, 2, 3, 4, 4, 4, 4]
start = pd.to_datetime(["2019-10-21-16:20:00", "2019-10-21-16:22:00", "2019-10-21-16:22:00", "2019-10-21-16:15:00",
"2019-10-21-16:22:00", "2019-10-21-16:58:00", "2019-10-21-17:02:00", "2019-10-21-17:03:00",
"2019-10-21-17:04:00", "2019-10-21-17:20:00"])
end = pd.to_datetime(["2019-10-21-16:25:00", "2019-10-21-16:24:00", "2019-10-21-16:24:00", "2019-10-21-16:18:00",
"2019-10-21-16:26:00", "2019-10-21-17:02:00", "2019-10-21-17:06:00", "2019-10-21-17:07:00",
"2019-10-21-17:08:00", "2019-10-21-17:22:00"])
cols = ["id", "group", "start", "end"]
df = pd.DataFrame(dict(zip(cols, [ids, group, start, end])))
到目前为止,我尝试过的方法显然是不正确的。我试过分组,然后找到该组每个开始和结束的最小值和最大值,然后将该间隔设置为总和。这种方法是不正确的,因为它还将包含间隔中的间隙。
gr = df.groupby("group").apply(lambda x : x.end.max() - x.start.min())
df['total_time'] = df.group.map(gr)
请您参考如下方法:
首先,添加一个列来跟踪到目前为止看到的最晚结束时间(但只考虑同一组):
df['notbefore'] = df.groupby('group').end.shift().cummax()
它移动了 1 位,以反射(reflect)在前几行中看到的最晚结束时间,不包括同一行。在 cummax() 之前使用 shift() 很重要,否则 shift 会在组之间“泄漏”值。
然后添加一个包含“有效”开始时间的列:
df['effstart'] = df[['start', 'notbefore']].max(1)
这是经过修改的开始时间,因此它不早于任何之前的结束时间(以避免重叠)。
然后计算覆盖的总秒数:
df['effsec'] = (df.end - df.effstart).clip(np.timedelta64(0))
df 现在是:
id group start end notbefore effstart effsec
0 0 0 2019-10-21 16:20:00 2019-10-21 16:25:00 NaT 2019-10-21 16:20:00 00:05:00
1 1 1 2019-10-21 16:22:00 2019-10-21 16:24:00 NaT 2019-10-21 16:22:00 00:02:00
2 2 1 2019-10-21 16:22:00 2019-10-21 16:24:00 2019-10-21 16:24:00 2019-10-21 16:24:00 00:00:00
3 3 2 2019-10-21 16:15:00 2019-10-21 16:18:00 NaT 2019-10-21 16:15:00 00:03:00
4 4 2 2019-10-21 16:22:00 2019-10-21 16:26:00 2019-10-21 16:24:00 2019-10-21 16:24:00 00:02:00
5 5 3 2019-10-21 16:58:00 2019-10-21 17:02:00 NaT 2019-10-21 16:58:00 00:04:00
6 6 4 2019-10-21 17:02:00 2019-10-21 17:06:00 NaT 2019-10-21 17:02:00 00:04:00
7 7 4 2019-10-21 17:03:00 2019-10-21 17:07:00 2019-10-21 17:06:00 2019-10-21 17:06:00 00:01:00
8 8 4 2019-10-21 17:04:00 2019-10-21 17:08:00 2019-10-21 17:07:00 2019-10-21 17:07:00 00:01:00
9 9 4 2019-10-21 17:20:00 2019-10-21 17:22:00 2019-10-21 17:08:00 2019-10-21 17:20:00 00:02:00
获取最终结果:
df.groupby('group').effsec.sum()
这给了你:
group
0 00:05:00
1 00:02:00
2 00:05:00
3 00:04:00
4 00:08:00
