我有一个包含3列的数据框,其中包含id,时间戳和事件类型:
id timestamp event_type
___________________________
0 1 2019-10-01 E1
1 1 2019-10-03 E3
2 2 2019-10-04 E3
3 2 2019-10-05 E4
4 2 2019-10-06 E1
5 1 2019-10-07 E3
6 1 2019-10-07 E4
7 1 2019-10-13 E3
8 2 2019-10-22 E5
我正在寻找一种汇总方法,以便将属于同一id且时延
即第0行和第1行应显示为一个列表,因为它们的时间戳记相隔不超过3天。
所以我想要的输出如下:
id2 event_hist
_______________
0 1-1 [E1, E3]
1 2-1 [E3, E4, E1]
2 1-2 [E3, E4]
3 1-3 [E3]
4 2-2 [E5]
id2列只是第一个数据帧的id,针对每个新序列进行迭代。
我可以编写一个函数来实现所需的结果,但是有内置方法吗? 最蟒蛇的方式是什么获得所需的输出?
答案 0 :(得分:2)
如果列时间戳不是日期时间,则从该日期开始
df['timestamp'] = pd.to_datetime(df['timestamp'])
t = df.groupby('id').apply(lambda g: g.rolling('3d', on='timestamp').count())
new = df.groupby(t['id'].le(t.shift()['id']).cumsum()) \
.agg(event_hist=('event_type', list), id2=('id', 'first'))
new['id2'] = new['id2'].astype(str) + \
'-' + \
new.groupby('id2').cumcount().add(1).astype(str)
产生
hist id2
id
0 [E1, E3] 1-1
1 [E3, E4, E1] 2-1
2 [E3, E4] 1-2
3 [E3] 1-3
4 [E5] 2-2
答案 1 :(得分:1)
我找到了我的问题的答案,这似乎行得通。尽管我认为@ splash58提出的答案更有效,并且使用更少的行和更多的内置函数。
def get_aggregate_by_lag(df, idcol, datecol, valuecol, max_lag):
import pandas as pd
res_dict = {}
for id in df[idcol].unique():
sub_df = df[df[idcol] == id].reset_index(drop=True)
current_sequence = [sub_df[valuecol][0]]
sequence_counter = 1
if len(sub_df) == 1:
res_dict[f"{id}-{sequence_counter}"] = [current_sequence]
continue
for i in range(1,len(sub_df)):
if (sub_df[datecol][i] - sub_df[datecol][i-1]).days <= max_lag:
current_sequence.append(sub_df[valuecol][i])
if i == len(sub_df)-1:
res_dict[f"{id}-{sequence_counter}"] = [current_sequence]
else:
res_dict[f"{id}-{sequence_counter}"] = [current_sequence]
sequence_counter += 1
current_sequence = [sub_df[valuecol][i]]
return pd.DataFrame.from_dict(res_dict, columns=["hist"], orient="Index")