如何基于多列数据动态生成结构化文本列

本文介绍如何在pandas中按逻辑分组(如连续相同“head”值),提取首名、筛选非首名成员,并拼接为定制化邀请语句,最终生成新列“message”。

在实际数据分析中,常需将结构化表格数据(如分组名单)转化为自然语言文本(如个性化邀请函)。本例的关键挑战在于:不能简单按head字段全量分组(因为Abba As出现两次且中间被Bella Bi隔开),而应识别“连续块”——即保持原始顺序下相邻且head值相同的行构成一个逻辑单元。

为此,我们使用 df['head'].ne(df['head'].shift()).cumsum() 构造连续分组标识:

  • df['head'].shift() 将head列下移一行;
  • .ne()(not equal)生成布尔序列,标记每行是否与前一行不同;
  • .cumsum() 对该布尔序列累积求和,使每个连续相同head块获得唯一整数标签(如 [1,1,1,2,2,2,3,3,3])。

随后,联合head与该连续标签进行双重分组(sort=False 保留原始顺序),并在每组内应用自定义函数:

def message(g):
    head_full = g.name[0]  # 获取当前组的 head 值(如 'Abba As')
    head_first = head_full.split()[0]  # 提取首名 'Abba'
    # 筛出 members 中不等于首名的成员,并用 ' and ' 连接
    others = ' and '.join(m for m in g['members'] if m != head_first)
    return f'Hi {head_first}, we invite you, {others}. Please use "{head_full}" when arriving.'

# 执行分组与映射
group_id = df['head'].ne(df['head'].shift()).cumsum()
result = (df.groupby(['head', group_id], sort=False)
          .apply(message)
          .droplevel(1)  # 移除辅助分组层级(group_id)
          .reset_index(name='message'))

⚠️ 注意事项:

  • 若某组中members全部等于head_first(如仅含Abba),others将为空字符串,导致语句变为 "Hi Abba, we invite you, . Please..." —— 建议增强鲁棒性:
    others = ' and '.join(m for m in g['members'] if m != head_first)
    others = others if others else "no 

    one else"
  • g.name[0] 安全的前提是分组键为元组 ('head', group_id),此时 g.name 形如 ('Abba As', 1);若仅单键分组,g.name 即为标量。
  • 输出自动去重并保持原始块顺序,无需额外排序。

该方法兼顾逻辑准确性与可扩展性,适用于会议签到、邮件模板生成、报告摘要等场景。