在Pandas中实现类似PostgreSQL array_agg的窗口聚合(保留所有行)
解决方案
首先修正你原始代码中的笔误:testdf是未定义变量,需改为df,同时可以用更简洁的方式生成span列:
import pandas as pd # 初始化数据 df = pd.DataFrame({ 'cid': ['A','B','C','D','E','F'], 'mid': ['1','1','2','2','2','3'], 'date_start': ['2019-05-17', '2020-01-20', '2018-02-10','2019-03-10','2020-03-10', '2018-04-11'], 'date_end': ['2020-05-17', '2021-01-20', '2019-02-10', '2020-03-10', '2021-03-15', '2021-04-11'] }) # 转换日期格式并生成span列 df['date_start'] = pd.to_datetime(df['date_start']).dt.date df['date_end'] = pd.to_datetime(df['date_end']).dt.date df['span'] = list(zip(df['date_start'], df['date_end']))
方法一:自定义分组遍历函数
通过遍历每个mid分组内的行,维护一个累积列表记录前序所有span,逻辑与PostgreSQL窗口函数完全对齐:
def generate_prev_spans(group): cumulative_spans = [] prev_dates = [] for span in group['span']: # 先存入当前累积的前序span(第一行为空) prev_dates.append(tuple(cumulative_spans) if cumulative_spans else None) # 将当前span加入累积列表,供后续行使用 cumulative_spans.append(span) group['prev_dates'] = prev_dates return group # 应用函数并保留原表结构 df = df.groupby('mid', group_keys=False).apply(generate_prev_spans)
方法二:使用expanding窗口(简洁版)
利用expanding窗口获取从分组开头到当前行的所有元素,再剔除当前行元素得到前序集合:
df['prev_dates'] = df.groupby('mid')['span'].expanding().apply( lambda x: tuple(x[:-1]) if len(x) > 1 else None ).reset_index(level=0, drop=True)
最终结果
执行后得到的DataFrame与预期完全一致:
cid mid span prev_dates 0 A 1 (2019-05-17, 2020-05-17) None 1 B 1 (2020-01-20, 2021-01-20) ((2019-05-17, 2020-05-17),) 2 C 2 (2018-02-10, 2019-02-10) None 3 D 2 (2019-03-10, 2020-03-10) ((2018-02-10, 2019-02-10),) 4 E 2 (2020-03-10, 2021-03-15) ((2018-02-10, 2019-02-10), (2019-03-10, 2020-03-10)) 5 F 3 (2018-04-11, 2021-04-11) None
关于你之前尝试方法的问题
df.groupby('mid')['span'].transform(lambda x: tuple(x)):会将整个分组的所有span存入每一行,而非仅前序行;df.groupby('mid')['span'].agg(lambda x: tuple(x)):仅返回每个分组的聚合结果(一行),无法保留原表的所有行结构。
内容的提问来源于stack exchange,提问作者nakkhatra-opti
相关产品推荐
相关产品推荐

