Pandas行操作优化:基于[StudentNo,Time]分组添加科目组合行的更优实现方案
高效生成科目组合行的Pandas优化方案
嘿,我来给你分享一个更简洁高效的实现思路,不用写几十行循环代码,靠Pandas的原生分组操作就能轻松搞定需求!
核心思路
我们可以利用groupby按[StudentNo, Time]分组,然后对每个分组里的Subject列生成两两组合,再把这些组合映射成新的行,最后和原数据合并即可。这种方式是向量化/批量处理,比逐个遍历StudentNo的循环效率高得多,尤其是数据量较大的时候优势更明显。
完整代码实现
import pandas as pd from itertools import combinations # 原DataFrame df = pd.DataFrame( [[1,'A','10:10'],[1,'B','10:10'],[1,'C','10:10'],[1,'D','10:10'],[1,'E','2:11'],[1,'B','2:11'],[2,'B','12:01'], [2,'C','12:01'],[3,'A','13:22']], columns=['StudentNo','Subject','Time'] ) # 定义分组处理函数:生成当前组的科目两两组合行 def generate_combinations(group): # 提取当前组的唯一科目列表 subjects = group['Subject'].unique().tolist() # 生成所有两两不重复的组合 combos = combinations(subjects, 2) # 把组合转换成用冒号连接的字符串 combo_subjects = [':'.join(combo) for combo in combos] # 构造新的DataFrame,复用当前组的StudentNo和Time return pd.DataFrame({ 'StudentNo': [group['StudentNo'].iloc[0]] * len(combo_subjects), 'Subject': combo_subjects, 'Time': [group['Time'].iloc[0]] * len(combo_subjects) }) # 对每个[StudentNo, Time]分组应用函数,得到所有组合行 combo_df = df.groupby(['StudentNo', 'Time']).apply(generate_combinations).reset_index(drop=True) # 合并原数据和组合行,得到最终结果 final_df = pd.concat([df, combo_df], ignore_index=True) # 可选:按StudentNo和Time排序,让结果更规整 final_df = final_df.sort_values(['StudentNo', 'Time', 'Subject']).reset_index(drop=True) print(final_df)
代码说明
- 分组处理:
groupby(['StudentNo', 'Time'])把数据按学生和时间分成独立的组,每个组对应同一学生同一时间的所有科目。 - 生成组合:用
itertools.combinations生成科目列表的两两不重复组合(比如只生成A:B,不会重复生成B:A),避免冗余数据。 - 构造新行:每个组合行复用当前组的StudentNo和Time,保证数据对应关系准确。
- 合并数据:用
pd.concat把原数据和新生成的组合行合并,最后排序让结果更清晰易读。
优势对比
- 原来的循环方法是Python级别的逐学生处理,当数据量很大时(比如几千个学生),速度会显著变慢;
- 这个方案用Pandas的
groupby.apply批量处理,内部基于向量化操作,效率提升非常明显,同时代码更简洁易读,维护成本更低。
内容的提问来源于stack exchange,提问作者kalaiyarasi Uma
相关产品推荐
相关产品推荐

