Python,Pandas:如何根据开始时间和结束时间合并数据帧的行
所以我有一个这样的数据帧:Python,Pandas:如何根据开始时间和结束时间合并数据帧的行,python,pandas,Python,Pandas,所以我有一个这样的数据帧: Start Time End Time IDs 15:02:13 15:10:24 BAMB30 19:46:19 19:46:29 BHI110 19:47:01 19:57:04 BHI110 19:47:01 19:56:58 BHI110 19:47:01 19:56:59 BHI110 12:01:46 12:06:30 A
Start Time End Time IDs
15:02:13 15:10:24 BAMB30
19:46:19 19:46:29 BHI110
19:47:01 19:57:04 BHI110
19:47:01 19:56:58 BHI110
19:47:01 19:56:59 BHI110
12:01:46 12:06:30 AKB286
Start Time End Time IDs Event
15:02:13 15:10:24 BAMB30
19:46:19 19:46:29 BHI110
19:47:01 19:57:04 BHI110 1
19:47:01 19:56:58 BHI110 1
19:47:01 19:56:59 BHI110 1
12:01:46 12:06:30 AKB286
我想将行或(行中的ID)分组为一个名为“事件”的东西,其定义如下:
(sid==tDlt.id)
放在代码的else条件中
但我在某些部分使用以下方法得到了不正确的结果:
如您所见,我希望单个事件具有不同的ID,但它仍然使用一些相同的ID进行分组。我在代码中哪里出错了
注意:这些不是我在数据框中拥有的唯一列。但是,在查找事件时,只有上述列才起作用。
谢谢大家! 为了给出一个更有启发性的例子,我举了以下例子 源数据帧:
Start Time End Time IDs C1 C2
0 15:02:13 15:10:24 BAMB30 X9 Y9
1 19:46:19 19:46:29 BHI110 X9 Y9
2 19:47:01 19:57:04 BHI110 D2 F2
3 19:47:01 19:56:58 BHI110 D2 E2
4 19:47:01 19:56:59 BHI110 D2 E2
5 20:00:02 20:20:00 BHI110 G3 H3
6 20:01:03 20:21:16 BHI110 G3 H3
7 20:15:00 20:23:20 BHI110 X9 Y9
8 12:01:46 12:06:30 AKB286 A1 B1
9 12:02:48 12:06:50 AKB286 A1 B1
10 12:02:50 12:06:55 AKB286 A1 C1
我添加了C1列和C2列(在
根据您的评论,当前组)
由于开始时间和结束时间列都是字符串类型,
第一步是将它们转换为Timedelta:
然后,我定义了一个将被视为事件的组的大小限制。
你写了这个限制==5,但是因为你和我的数据
样本只包含较小的组,我将此限制设置为2:
sizeLimit = 2
当然,在真实数据上运行我的代码时,将此限制更改为
你需要什么都行
然后定义一个函数来检查当前
行和“起始行”并生成“事件编号”:
由于其内部属性的使用,它是一个“带内存的函数”,
在“开始”和“结束”属性中保留来自
上一行和ev属性-事件编号
此函数将应用于数据帧的每一行,但在
它的start属性将设置为None,以提供正确的处理
第一排
请注意,起始行已设置为:
- 在第一行(当tDlt.start为None时)
- 在每一行上,从“起始”行开始“时间太远”或 C1或C2与“起始”行不同
- 从0开始,
- 在任何条件下继续当前组时增加 没有得到满足
- 对于所有组,即使是低于大小限制的组
tDlt.start = None
ev = df.sort_values(['Start Time', 'End Time']).apply(tDlt, axis=1)
结果(对于我的数据样本)是:
当然,由于之前的排序,行顺序不同
应用程序
检查索引为3、4和2的行。第三排是最早的
从这个群体。第4行在同一组内(满足所有条件)。
但第2行在C2列中有不同的值,所以它会启动一个新的
小组
- 取每组(按值)并检查其大小
- 如果至少有sizeLimit行,则返回原始组 数字,但作为字符串(对于每行)
- 否则,返回一个空字符串(也适用于每一行)-返回 实际取消
8 0
9 0
10
0
1
3 4
4 4
2
5 6
6 6
7
dtype: object
df['Event'] = ev[ev != ''].groupby(ev, sort=False).ngroup() + 1
步骤:
- 从ev中获取非空元素
- 将它们(按其值)分组
- 返回“全局”组编号,从1开始。注意 “初始组号”(到目前为止已计算)在此处更改 进入连续的
- “太短”组的单元格包含NaN
- 元素为浮动类型
df.Event.replace(np.nan, '', inplace=True)
Start Time End Time IDs C1 C2 Event
8 12:01:46 12:06:30 AKB286 A1 B1 1
9 12:02:48 12:06:50 AKB286 A1 B1 1
10 12:02:50 12:06:55 AKB286 A1 C1
0 15:02:13 15:10:24 BAMB30 X9 Y9
1 19:46:19 19:46:29 BHI110 X9 Y9
3 19:47:01 19:56:58 BHI110 D2 E2 2
4 19:47:01 19:56:59 BHI110 D2 E2 2
2 19:47:01 19:57:04 BHI110 D2 F2
5 20:00:02 20:20:00 BHI110 G3 H3 3
6 20:01:03 20:21:16 BHI110 G3 H3 3
7 20:15:00 20:23:20 BHI110 X9 Y9
如你所见:
- 前两行在时间上足够近,因此是事件1
- 第三行的开始时间与前一行的距离太远, 因此,它未被纳入上述组
- 它离下一排也太远了,所以它们不能在一起 在事件中分组
- 第3行和第4行构成下一组
- 由于C2中的值不同,不包括第2行
- 等等
def tDlt(row):
id, st, et, c1, c2 = row[['IDs', 'Start Time', 'End Time', 'C1', 'C2']]
if tDlt.start is None:
tDlt.id, tDlt.start, tDlt.end, tDlt.ev, tDlt.c1, tDlt.c2 = id, st, et, 0, c1, c2
else:
if id != tDlt.id\
or ((st - tDlt.start).total_seconds() > 120)\
or ((et - tDlt.end).total_seconds() > 120)\
or (c1 != tDlt.c1) or (c2 != tDlt.c2):
tDlt.id, tDlt.start, tDlt.end, tDlt.c1, tDlt.c2 = id, st, et, c1, c2
tDlt.ev += 1
return tDlt.ev
在tDlt.start=None
之后,将下一条指令更改为:
ev = df.sort_values(['IDs', 'Start Time', 'End Time']).apply(tDlt, axis=1)
我想
df.Event.replace(np.nan, '', inplace=True)
Start Time End Time IDs C1 C2 Event
8 12:01:46 12:06:30 AKB286 A1 B1 1
9 12:02:48 12:06:50 AKB286 A1 B1 1
10 12:02:50 12:06:55 AKB286 A1 C1
0 15:02:13 15:10:24 BAMB30 X9 Y9
1 19:46:19 19:46:29 BHI110 X9 Y9
3 19:47:01 19:56:58 BHI110 D2 E2 2
4 19:47:01 19:56:59 BHI110 D2 E2 2
2 19:47:01 19:57:04 BHI110 D2 F2
5 20:00:02 20:20:00 BHI110 G3 H3 3
6 20:01:03 20:21:16 BHI110 G3 H3 3
7 20:15:00 20:23:20 BHI110 X9 Y9
def tDlt(row):
id, st, et, c1, c2 = row[['IDs', 'Start Time', 'End Time', 'C1', 'C2']]
if tDlt.start is None:
tDlt.id, tDlt.start, tDlt.end, tDlt.ev, tDlt.c1, tDlt.c2 = id, st, et, 0, c1, c2
else:
if id != tDlt.id\
or ((st - tDlt.start).total_seconds() > 120)\
or ((et - tDlt.end).total_seconds() > 120)\
or (c1 != tDlt.c1) or (c2 != tDlt.c2):
tDlt.id, tDlt.start, tDlt.end, tDlt.c1, tDlt.c2 = id, st, et, c1, c2
tDlt.ev += 1
return tDlt.ev
ev = df.sort_values(['IDs', 'Start Time', 'End Time']).apply(tDlt, axis=1)
11 20:00:02 20:20:00 XXX110 G3 H3
12 20:01:03 20:21:16 XXX110 G3 H3
Start Time End Time IDs C1 C2 Event
8 12:01:46 12:06:30 AKB286 A1 B1 1
9 12:02:48 12:06:50 AKB286 A1 B1 1
10 12:02:50 12:06:55 AKB286 A1 C1
0 15:02:13 15:10:24 BAMB30 X9 Y9
1 19:46:19 19:46:29 BHI110 X9 Y9
3 19:47:01 19:56:58 BHI110 D2 E2 2
4 19:47:01 19:56:59 BHI110 D2 E2 2
2 19:47:01 19:57:04 BHI110 D2 F2
5 20:00:02 20:20:00 BHI110 G3 H3 3
6 20:01:03 20:21:16 BHI110 G3 H3 3
7 20:15:00 20:23:20 BHI110 X9 Y9
11 20:00:02 20:20:00 XXX110 G3 H3 4
12 20:01:03 20:21:16 XXX110 G3 H3 4