基于简单多数规则聚合DataFrame预测列的技术实现问题
问题
我有一个来自模型预测的pandas DataFrame,示例如下:
import pandas as pd df = pd.DataFrame({ 'trip-id': [8,8,8,8,8,8,8,8,4,4,4,4,4,4,4,4,4,4,4,4], 'segment-id': [1,1,1,1,1,1,1,1,0,0,0,0,0,0,5,5,5,5,5,5], 'true_label': [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], 'prediction': [3, 3, 3, 1, 2, 4, 0, 0, 3, 3, 3, 0, 1, 2, 3, 3, 1, 1, 2, 2] }) # 输出的DataFrame结构: # trip-id segment-id true_label prediction # 0 8 1 3 3 # 1 8 1 3 3 # 2 8 1 3 3 # 3 8 1 3 1 # 4 8 1 3 2 # 5 8 1 3 4 # 6 8 1 3 0 # 7 8 1 3 0 # 8 4 0 3 3 # 9 4 0 3 3 # 10 4 0 3 3 # 11 4 0 3 0 # 12 4 0 3 1 # 13 4 0 3 2 # 14 4 5 3 3 # 15 4 5 3 3 # 16 4 5 3 1 # 17 4 5 3 1 # 18 4 5 3 2 # 19 4 5 3 2
该数据集包含行程段实例的预测值与真实标签,需要基于以下简单多数规则生成段级预测汇总:
- 取段内出现次数占简单多数的预测值作为该段的预测结果;
- 若出现多数值平局,则选取与
true_label匹配的值作为段预测结果; - 若平局且无匹配真实标签的值,则选取平局值中在DataFrame中最先出现的那个。
当前使用的代码如下:
segments_summary = ( df['true_label'].eq(df['prediction']) .groupby([df['true_label'],df['trip-id'], df['segment-id']]).mean() .ge(0.5) .groupby(level='true_label').agg(['size','sum']) .rename(columns={'size':'total-segments','sum':'correctly-predicted'})\ .assign(recall = lambda x: round(x['correctly-predicted']/x['total-segments'], 2)) .reindex(range(5), fill_value='-') .reset_index())
运行结果不符合预期:
true_label total-segments correctly-predicted recall 0 0 - - - 1 1 - - - 2 2 - - - 3 3 3 1 0.33 4 4 - - -
根据规则,3个段都应被正确预测:
- trip 8, segment 1:3为多数值,应预测为3;
- trip 4, segment 0:3为多数值,应预测为3;
- trip 4, segment 5:出现平局,应选取匹配true_label的3作为预测结果。
期望得到如下结果:
true_label total-segments correctly-predicted recall 0 0 - - - 1 1 - - - 2 2 - - - 3 3 3 3 1.0 4 4 - - -
请帮忙修正代码以得到符合规则的段级预测汇总。
解决方案
原代码的问题在于直接计算段内预测正确的比例并判断是否≥0.5,这不符合自定义的多数规则。需要先按照规则生成每个段的最终预测值,再统计正确数。
修正后的代码如下:
import pandas as pd def get_segment_prediction(group): # 统计每个预测值的出现次数 pred_counts = group['prediction'].value_counts() # 获取最高出现次数 max_count = pred_counts.max() # 筛选出出现次数等于最高次数的候选值 candidates = pred_counts[pred_counts == max_count].index.tolist() # 规则2:如果真实标签在候选中,选它 true_label = group['true_label'].iloc[0] if true_label in candidates: return true_label # 规则3:否则选候选中最先出现的那个 else: for pred in group['prediction']: if pred in candidates: return pred # 规则1:如果只有一个候选(多数),直接返回 return candidates[0] # 按true_label、trip-id、segment-id分组,生成每个段的预测结果 segment_predictions = df.groupby(['true_label', 'trip-id', 'segment-id']).apply(get_segment_prediction).reset_index(name='segment_pred') # 统计每个true_label的总段数和正确预测数 segments_summary = ( segment_predictions .assign(correct=lambda x: x['true_label'] == x['segment_pred']) .groupby('true_label') .agg( total_segments=('segment_pred', 'size'), correctly_predicted=('correct', 'sum') ) .assign(recall=lambda x: round(x['correctly_predicted'] / x['total_segments'], 2)) .reindex(range(5), fill_value='-') .rename(columns={ 'total_segments': 'total-segments', 'correctly_predicted': 'correctly-predicted' }) .reset_index() ) print(segments_summary)
代码说明:
- 自定义函数
get_segment_prediction:严格实现三个规则的逻辑:- 先统计段内各预测值的出现次数,筛选出出现次数最多的候选值;
- 检查真实标签是否在候选列表中,是则直接返回;
- 若不在,遍历原分组的预测值序列,返回第一个出现的候选值;
- 若只有一个候选(多数情况),直接返回该值。
- 分组生成段级预测:按
true_label、trip-id、segment-id分组,应用自定义函数得到每个段的最终预测结果。 - 统计汇总结果:计算每个
true_label对应的总段数、正确预测数和召回率,最后按要求格式填充缺失值并输出。
运行该代码后,将得到期望的结果:
true_label total-segments correctly-predicted recall 0 0 - - - 1 1 - - - 2 2 - - - 3 3 3 3 1.0 4 4 - - -
内容的提问来源于stack exchange,提问作者Amina Umar
相关产品推荐
相关产品推荐

