You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:35:33