基于DataFrame分组结果的两表合并优化方案咨询
优化方案:更高效简洁的DataFrame分组与合并实现
当然有更高效、更简洁的实现方式!咱们先梳理下你原代码的核心逻辑:按object_id对DataFrame C分组,将每组指定列转为字典列表作为change_history,统计列表长度得到num_changes,最后和DataFrame A左连接。下面针对不同场景给出优化方案:
方案一:简化代码结构+矢量化计算(适合中小数据集)
原代码里的列重命名、单独重置索引可以合并为一步,同时计算num_changes时用**矢量化的str.len()**替代apply(lambda x: len(x))——后者是逐行执行Python循环,效率远低于矢量化操作。
import pandas as pd # 生成优化后的B,用链式调用简化流程 B = ( C.groupby('object_id') .apply(lambda x: x[['number', 'date', 'user_id', 'change']].to_dict('records')) .reset_index(name='change_history') # 直接指定列名,省去单独重命名步骤 .assign(num_changes=lambda df: df['change_history'].str.len()) # 矢量化计算长度 ) # 合并操作和原逻辑一致 data = A.merge(B, how='left', on='object_id')
方案二:高性能分组聚合(适合大数据集)
如果你的C数据集很大(比如百万行以上),groupby.apply()逐组处理的开销会比较明显。我们可以先通过agg(list)将每组的各列转为列表(这是pandas内部优化的矢量化操作),再构造字典列表,避免逐组调用to_dict():
import pandas as pd # 先按object_id分组,将指定列转为列表 agg_result = C.groupby('object_id')[['number', 'date', 'user_id', 'change']].agg(list) # 把每组的列列表转为字典列表 B = agg_result.apply( lambda row: [dict(zip(row.index, vals)) for vals in zip(*row.values)], axis=1 ).reset_index(name='change_history') # 同样用矢量化操作计算变更次数 B['num_changes'] = B['change_history'].str.len() # 合并 data = A.merge(B, how='left', on='object_id')
为什么这些方案更优?
- 矢量化操作:
str.len()是pandas底层优化的向量化方法,比逐行执行len()的apply快数倍甚至数十倍。 - 代码简洁性:用链式调用(
groupby().apply().reset_index().assign())减少冗余代码,逻辑更连贯。 - 大数据适配:方案二的
agg(list)避免了逐组的Python循环,利用pandas的C级优化提升处理速度,数据量越大优势越明显。
内容的提问来源于stack exchange,提问作者daiyue
相关产品推荐
相关产品推荐

