Pandas实战:学生成绩重评后捕获更新列名至指定单列
问题描述
现有学生成绩重评前、后两个数据集,合并后需新增anyimprovement和improvedfield两列。目前anyimprovement列已完成(用于标记记录是否有改进、是否为新条目),但需要完善improvedfield列的实现逻辑:
- 同一主键(name、class、exam)的记录,将重评后发生变化的列名(如科目成绩、result等)用逗号分隔存入该列;
- 无改进时标记为“no improvement”;
- 新条目标记为“new entry”。
当前使用的代码如下:
# 拼接name、class、exam生成主键列,拼接maths、physics、chemistry生成次键列 concatdf['PrimaryKey'] = concatdf['name'] + '_' + concatdf['class'] + '_' + concatdf['exam'] concatdf['SecondaryKey'] = concatdf['maths'].astype(str) + '_' + concatdf['physics'].astype(str) + '_' + concatdf['chemistry'].astype(str) dupedf = concatdf.loc[concatdf.duplicated(subset=['PrimaryKey', 'SecondaryKey'],keep=False)] dupedf1 = concatdf.loc[concatdf.duplicated(subset=['PrimaryKey'],keep=False)] for i,j in dupedf.iterrows(): for k,l in dupedf1.iterrows(): if l['PrimaryKey'] == j['PrimaryKey']: dupedf = dupedf.drop_duplicates(subset=['PrimaryKey','SecondaryKey'],keep='last') dupedf['any improvement'] = 'No' # dupedf['improved subject'] = ' ' else: dupedf1 = dupedf1.drop_duplicates(subset=['SecondaryKey'],keep=False) dupedf1 = dupedf1.drop_duplicates(subset=['PrimaryKey'],keep='last') dupedf1['any improvement'] = 'Yes' # dupedf1['improved subject'] = 'column name'
解决方案
思路说明
原代码用双重循环处理重复数据,效率低且逻辑混乱。推荐按主键分组对比的方式,步骤如下:
- 给重评前、后的数据添加版本标识,方便区分新旧记录;
- 按主键
PrimaryKey分组,判断每组记录数量:1条则为新条目,2条则对比字段差异; - 根据对比结果填充
anyimprovement和improvedfield列。
实现代码
首先处理数据合并与标识添加:
import pandas as pd # 假设重评前数据为df_pre,重评后为df_post df_pre['version'] = 'pre' # 标记重评前数据 df_post['version'] = 'post' # 标记重评后数据 concatdf = pd.concat([df_pre, df_post], ignore_index=True) # 生成主键列 concatdf['PrimaryKey'] = concatdf['name'] + '_' + concatdf['class'] + '_' + concatdf['exam'] # 初始化目标列 concatdf['anyimprovement'] = '' concatdf['improvedfield'] = ''
然后分组处理差异:
# 定义需要对比的字段(根据实际需求调整) compare_columns = ['maths', 'physics', 'chemistry', 'result'] # 按主键分组遍历 for pk, group in concatdf.groupby('PrimaryKey'): if len(group) == 1: # 分组仅一条记录,判定为新条目 concatdf.loc[concatdf['PrimaryKey'] == pk, ['anyimprovement', 'improvedfield']] = 'new entry' else: # 获取重评前后的单条记录 pre_record = group[group['version'] == 'pre'].iloc[0] post_record = group[group['version'] == 'post'].iloc[0] # 筛选出有变化的字段 changed_fields = [col for col in compare_columns if pre_record[col] != post_record[col]] if not changed_fields: # 无字段变化 concatdf.loc[concatdf['PrimaryKey'] == pk, 'anyimprovement'] = 'No' concatdf.loc[concatdf['PrimaryKey'] == pk, 'improvedfield'] = 'no improvement' else: # 有字段变化 concatdf.loc[concatdf['PrimaryKey'] == pk, 'anyimprovement'] = 'Yes' concatdf.loc[concatdf['PrimaryKey'] == pk, 'improvedfield'] = ', '.join(changed_fields)
关键说明
- 版本标识是核心:如果合并时没有区分重评前后,可通过数据来源(比如原数据集的顺序)补充这个标识;
- 对比字段可自定义:
compare_columns列表根据实际需要调整,比如加入其他科目或评价字段; - 避免双重循环:用
groupby分组处理比原代码的双重循环效率高得多,尤其当数据量较大时。
内容的提问来源于stack exchange,提问作者Beginner
相关产品推荐
相关产品推荐

