如何用Pandas将客户订单DataFrame按姓名邮箱分组并格式化输出
解决方案
要实现按name和email分组后仅首行显示这两个字段的需求,核心是格式化显示而非修改数据结构。以下是两种可行方案:
方案1:修改DataFrame替换重复值(适合文本输出)
通过将同一组内重复的name和email替换为空字符串,实现目标显示效果:
import pandas as pd # 构造示例数据 data = { 'name': ['jane', 'john', 'john', 'jim', 'jim', 'bill', 'jim', 'jane', 'john', 'jim'], 'email': ['jane@email.com', 'john@email.com', 'john@email.com', 'jim@email.com', 'jim@email.com', 'bill@email.com', 'jim@email.com', 'jane@email.com', 'john@email.com', 'jim@email.com'], 'product': ['Red Shirt', 'Green Shirt', 'Red Shirt', 'Green Shirt', 'Blue Shirt', 'Green Shirt', 'Blue Shirt', 'Blue Shirt', 'Blue Shirt', 'Green Shirt'], 'qty_ordered': [2, 2, 1, 1, 2, 1, 1, 2, 1, 2] } df = pd.DataFrame(data) # 1. 先按name和email排序,确保同组数据连续 df_sorted = df.sort_values(['name', 'email']).reset_index(drop=True) # 2. 复制DataFrame并替换重复的name和email为空字符串 df_formatted = df_sorted.copy() df_formatted['name'] = df_formatted['name'].mask(df_formatted['name'] == df_formatted['name'].shift(1), '') df_formatted['email'] = df_formatted['email'].mask(df_formatted['email'] == df_formatted['email'].shift(1), '') # 打印结果(去掉索引) print(df_formatted.to_string(index=False))
输出结果:
name email product qty_ordered bill bill@email.com Green Shirt 1 jane jane@email.com Red Shirt 2 Blue Shirt 2 jim jim@email.com Green Shirt 1 Blue Shirt 2 Blue Shirt 1 Green Shirt 2 john john@email.com Green Shirt 2 Red Shirt 1 Blue Shirt 1
方案2:使用Pandas Styler(适合可视化展示,如Jupyter Notebook)
如果不想修改原始数据,可通过Styler工具在显示时隐藏重复值:
def hide_duplicate_values(val, prev_val): return '' if val == prev_val else val # 应用样式到name和email列 styled_df = df_sorted.style.apply( lambda col: [hide_duplicate_values(v, col.shift()[i]) for i, v in enumerate(col)], subset=['name', 'email'] ) # 在Jupyter中直接显示styled_df即可看到效果 styled_df
为什么你的之前尝试没成功?
你用groupby.apply()、melt()、pivot()等方法的思路偏了:
groupby的核心是数据聚合/转换,不是格式化显示;你之前的代码只是提取了分组后的字段,没有处理重复值的显示逻辑。melt()/pivot()是用于数据重塑(行转列或列转行),和当前的显示需求不匹配。
本质上,你需要的是对重复字段的显示隐藏,而非改变数据的结构或聚合方式。
内容的提问来源于stack exchange,提问作者Jakemoyo
相关产品推荐
相关产品推荐

