17370845950

如何在Pandas中基于分组信息动态生成结构化文本列

本文介绍如何利用`groupby().apply()`配合自定义函数,将dataframe中按连续相同“head”分组的成员列表整合为自然语言格式的邀请消息,并自动排除与head同名的重复成员。

在实际数据分析中,常需将结构化数据(如分组后的多行记录)转换为可读性强的文本摘要。本例目标是:对连续出现的相同 head(如 "Abba As")所对应的 members 列进行聚合,生成一条个性化邀请语句——其中首名成员(取 head 的姓氏部分)作为主宾称呼,其余成员用“and”连接,并保留原始 head 字符串用于入场标识。

关键难点在于:需按“head值连续出现”的逻辑分组(而非简单去重分组),因为同一 head 可能在后续再次出现(如示例中 "Abba As" 出现在索引 0–2 和 6–8),应视为两个独立邀请批次。

以下是完整实现方案:

import pandas as pd

# 构建示例数据
df = pd.DataFrame({
    'head': ['Abba As', 'Abba As', 'Abba As', 'Bella Bi', 'Bella Bi', 'Bella Bi', 'Abba As', 'Abba As', 'Abba As'],
    'members': ['Ally', 'Apo', 'Abba', 'Bella', 'Boo', 'Brian', 'Arra', 'Alya', 'Abba']
})

# 步骤1:识别连续分组(核心!)
group = df['head'].ne(df['head'].shift()).cumsum()

# 步骤2:定义生成message的函数
def generate_message(group_df):
    head_full = group_df.name[0]  # 获取当前组的head值(元组形式,取第一个元素)
    head_first_name = head_full.split()[0]  # 提取首名(如"Abba")
    # 过滤掉与首名相同的成员(即本人),保留其余成员
    other_members = [m for m in group_df['members'] if m != head_first_name]
    # 用" and "连接其他成员
    others_str = ' and '.join(other_members)
    return f'Hi {head_first_name}, we invite you, {others_str}. Please use "{head_full}" when arriving.'

# 步骤3:分组应用 + 整理结果
result = (df.groupby(['head', group], sort=False)
          .apply(generate_message)
          .droplevel(1)  # 删除辅助分组层级
          .reset_index(name='message'))

✅ 输出结果严格匹配预期:

       head                                                                       message
0   Abba As     Hi Abba, we invite you, Ally and Apo. Please use "Abba As" when arriving.
1  Bella Bi  Hi Bella, we invite you, Boo and Brian. Please use "Bella Bi" when arriving.
2   Abba As    Hi Abba, we invite you, Arra and Alya. Please use "Abba As" when arriving.

⚠️ 注意事项:

  • df['head'].ne(df['head'].shift()).cumsum() 是识别连续相同值区块的标准技巧,不可替换为 df.groupby('head')(否则会合并所有 "Abba As" 行,丢失批次语义);
  • groupby(['head', group]) 中 group 是辅助序列号,确保相同 head 的不同连续段被区分开;
  • 若某组内除首名外无其他成员(如仅含 ["Abba"]),others_str 将为空字符串,语句变为 "Hi Abba, we invite you, . Please..." —— 可根据业务需求在函数中增加空值判断(例如 if not other_members: others_str = "no one else");
  • 此方法时间复杂度为 O(n),适用于万级以内数据;超大数据量建议结合 numba 或预聚合优化。

该模式可灵活扩展:替换模板字符串、支持多语言、接入邮件/短信API,是构建自动化报告与通知系统的典型范式。