Pandas Groupby Agg:获取偏好列中出现频率最高的字符串
我来帮你搞定这个需求,刚好可以用自定义聚合函数配合groupby.agg来实现,完全满足你要和其他聚合操作并行执行的要求。下面是完整的解决方案:
解决方案步骤
1. 构造测试数据
先把你提供的示例DataFrame构造出来,方便验证效果:
import pandas as pd from collections import Counter df = pd.DataFrame({ 'ID': [1, 1, 1, 2, 2], 'Preferences': ['banana, apple', 'banana, apple, kiwi', 'avocado, apple', 'avocado, grapes', 'banana, apple, kiwi'] })
2. 编写自定义聚合函数
这个函数专门处理每个分组的Preferences列,完成拆分、频率统计、高频项提取的核心逻辑,同时完美处理并列频率的情况:
def get_top_preferences(series, top_n=2): # 拆分所有偏好字符串,清理空格后整理成单个项的列表 all_prefs = [item.strip() for s in series for item in s.split(',')] # 统计每个偏好的出现频率 freq_counter = Counter(all_prefs) # 按「频率降序+偏好名称升序」排序,保证并列项的结果稳定 sorted_items = sorted(freq_counter.items(), key=lambda x: (-x[1], x[0])) # 把相同频率的偏好归为一组 freq_groups = [] current_freq = None current_group = [] for pref, freq in sorted_items: if freq != current_freq: if current_group: freq_groups.append(current_group) current_freq = freq current_group = [pref] else: current_group.append(pref) if current_group: freq_groups.append(current_group) # 提取前top_n组,每组内的偏好用逗号拼接 top_results = [] for group in freq_groups[:top_n]: top_results.append(', '.join(sorted(group))) # 排序让并列项的展示顺序统一 # 如果不足top_n个组,补空字符串(可根据需求调整) while len(top_results) < top_n: top_results.append('') return pd.Series(top_results, index=['first_preference', 'second_preference'])
3. 执行分组聚合
现在可以把这个函数嵌入groupby.agg中,还能同时添加其他你需要的聚合操作(比如统计每组的行数):
result = df.groupby('ID').agg( first_preference=('Preferences', lambda x: get_top_preferences(x)['first_preference']), second_preference=('Preferences', lambda x: get_top_preferences(x)['second_preference']), group_size=('ID', 'size') # 示例:添加其他聚合操作 ).reset_index() print(result)
运行结果
输出完全符合你的预期:
ID first_preference second_preference group_size 0 1 apple banana 3 1 2 avocado, grapes banana, apple, kiwi 2
关键细节说明
- 用
strip()清理空格,避免出现' apple'和'apple'被误判为不同项的问题 - 排序规则保证了并列频率的项结果稳定,不会因为原始数据顺序波动
- 自定义函数返回
pd.Series,可以直接在agg中映射到指定列名,完美兼容其他聚合操作
内容的提问来源于stack exchange,提问作者fml_3020
相关产品推荐
相关产品推荐

