
本文介绍如何基于已排序的dataframe,按`head`列的连续分组提取首名、筛选非重复成员,并拼接为定制化邀请消息,最终生成包含规范格式文本的新列`message`。
在实际数据处理中,常需将多行结构化信息(如分组下的成员列表)聚合成一句自然语言描述。本例中,原始DataFrame已按逻辑顺序排列,目标是:对每个连续相同的head值块(而非全局去重分组),提取其对应的所有members,剔除与head首名相同的成员,再按指定模板生成个性化邀请语句。
关键难点在于:head值(如Abba As)在数据中多次出现且不连续(第0–2行和第6–8行均为Abba As),但需视为两个独立邀请批次——因此不能直接用 df.groupby('head'),而应识别连续段(run-length grouping)。
以下为完整实现方案:
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 = head_full.split()[0] # 提取首名,如'Abba'
# 过滤掉与首名相同的members(注意:区分大小写,此处假设严格匹配)
other_members = [m for m in group_df['members'] if m != head_first]
# 拼接为"X and Y"格式(支持2+个成员)
others_str = ' and '.join(other_members)
return f'Hi {head_first}, 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'))
print(result)✅ 输出效果:
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() 是识别连续段的标准范式,比 groupby().ngroup() 更精准适配本场景;
- 若members中存在大小写不一致(如'abba' vs 'Abba'),建议统一 .str.lower() 处理后再比较;
- 当某组内无其他成员(即所有members均等于首名),others_str为空字符串,语句会变为 "Hi X, we invite you, . Please..." —— 可在函数中添加 if not other_members: others_str = 'no one else' 做健壮性增强;
- 模板中的标点、空格需严格遵循业务要求,推荐将模板提取为常量字符串便于维护。
该方法兼具可读性与扩展性,适用于各类基于连续分组的文本聚合任务。








