
本文介绍如何在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 即为标量。
- 输出自动去重并保持原始块顺序,无需额外排序。
该方法兼顾逻辑准确性与可扩展性,适用于会议签到、邮件模板生成、报告摘要等场景。









