Pandas按student分组:将含A/B双等级的记录标记为‘both’的最优实现
更优的Pandas分组实现方案
针对你的需求,这里提供几种更简洁高效的实现方式,解决原代码存在的冗余、副作用问题:
方法一:直接分组聚合
通过groupby结合自定义聚合函数,一步完成判断与结果生成:
import pandas as pd df = pd.DataFrame({'student': 'AA AA AA BB BB BB CC CC CC CC'.split(), 'grade': ['B', 'B', 'B', 'A', 'A', 'B', 'B', 'B', 'B', 'B']}) result = df.groupby('student')['grade'].agg( lambda x: 'both' if {'A', 'B'}.issubset(x.unique()) else x.unique()[0] ).reset_index() print(result)
输出结果:
student grade 0 AA B 1 BB both 2 CC B
这种方式直接在分组后处理每个学生的等级集合,逻辑清晰,且不会修改原始DataFrame,避免意外副作用。
方法二:先构建映射字典再匹配
如果需要复用学生与等级标签的映射关系,可以先生成字典再构造结果:
# 生成每个学生的唯一等级集合 grade_sets = df.groupby('student')['grade'].apply(lambda x: set(x.unique())) # 转换为目标标签 grade_map = grade_sets.map(lambda s: 'both' if s == {'A', 'B'} else next(iter(s))) # 转为目标DataFrame result = grade_map.reset_index(name='grade')
原代码的可优化点
- 原代码依赖
crosstab生成交叉表,当等级类别较多时会占用额外内存,逻辑也相对绕; - 使用
inplace=True修改原始数据,容易引发意外副作用,建议始终返回新的DataFrame; - 最终生成的
AB不符合需求的both,需要额外替换,而上面的方法可直接生成目标标签。
内容的提问来源于stack exchange,提问作者Roy
相关产品推荐
相关产品推荐

