如何获取DataFrame中指定时间点后首次出现的新事件?
问题:获取个体时间序列中的首次新事件
原始数据
| id | time1 | time2 | time3 | event1 | event2 | event3 |
|---|---|---|---|---|---|---|
| a | 2011-04-22 | [] | 2016-06-07 | [apple, orange] | [] | [orange, grape] |
| b | 2010-07-15 | 2014-07-12 | 2015-05-10 | [apple] | [apple, orange] | [apple, orange, grape] |
需求说明
需要获取指定初始时间点(如time1)之后,每个后续时间点出现的首次新事件(即该事件未在之前所有时间点出现过),但当某时间列为空(无事件)时,原代码无法正确计算。
初始错误代码
def substracttest(i): if (i>2): df['new_event'+str(i)]=df['event'+str(i)].apply(lambda x: [k for k in x if k not in substracttest(i-1)]).values return(df['new_event'+str(i)]) else: df['new_event'+str(i)]=df['event'+str(i)].apply(lambda x: [k for k in x if k not in df['event'+str(i-1)]]).values return(df['new_event'+str(i)]) for j in range(2,4): substracttest(j)
错误输出
new_event1 new_event2 [] [orange, grape] [apple, orange] [apple, orange, grape]
期望输出
new_event1 new_event2 [] [grape] [orange] [grape]
调整后可行代码
import numpy as np def substracttest(i): if (i>2): df['new_event'+str(i)]=df.apply(lambda row : np.setdiff1d(row['event'+str(i)],row['new_event'+str(i-1)]), axis=1) for j in range(1,i): df['new_event'+str(i)]=df.apply(lambda row : np.setdiff1d(row['new_event'+str(i)],row['event'+str(j)]), axis=1) return(df) else: df['new_event'+str(i)]=df.apply(lambda row : np.setdiff1d(row['event'+str(i)],row['event'+str(i-1)]), axis=1) return(df) for j in range(2,4): substracttest(j)
其他可行实现思路
思路1:长表格式转换后处理
先将宽表转为长表(每个id-时间点为一行),过滤无事件行后按时间排序,通过累积事件集合计算新事件,更适配时间点数量不固定的场景:
import pandas as pd # 转换为长表格式 long_df = df.melt(id_vars=['id'], value_vars=[f'time{k}' for k in range(1,4)] + [f'event{k}' for k in range(1,4)], var_name='type', value_name='value') # 拆分时间点序号和类型(时间/事件) long_df['time_point'] = long_df['type'].str.extract('(\d+)') long_df['type'] = long_df['type'].str.replace('\d+', '') # 透视回宽表,按id和时间点分组 long_df = long_df.pivot(index=['id', 'time_point'], columns='type', values='value').reset_index() # 过滤无事件的行 long_df = long_df[long_df['event'].apply(lambda x: len(x) > 0)] # 按id和时间排序 long_df['time'] = pd.to_datetime(long_df['time']) long_df = long_df.sort_values(['id', 'time']) # 分组累积事件集合,计算新事件 def calculate_new_events(group): seen = set() new_events = [] for events in group['event']: new = [e for e in events if e not in seen] new_events.append(new) seen.update(events) group['new_event'] = new_events return group result = long_df.groupby('id').apply(calculate_new_events)
思路2:逐行遍历累积事件集合
直接对每行数据按时间顺序遍历事件列,维护已出现事件的集合,逻辑简单易理解:
# 定义时间列和事件列的范围 time_cols = [f'time{k}' for k in range(1,4)] event_cols = [f'event{k}' for k in range(1,4)] # 逐行处理每个个体的事件序列 for idx, row in df.iterrows(): seen = set() # 先加入初始时间点的所有事件 seen.update(row[event_cols[0]]) # 遍历后续每个时间点 for i in range(1, len(event_cols)): current_events = row[event_cols[i]] # 筛选出未出现过的新事件 new_events = [e for e in current_events if e not in seen] df.loc[idx, f'new_event{i}'] = new_events # 更新已出现事件集合 seen.update(current_events)
内容的提问来源于stack exchange,提问作者Anakorang
相关产品推荐
相关产品推荐

