如何将for循环改写为列表推导式或lambda函数优化Pandas自定义函数
原自定义函数的核心低效问题
- 逐客户循环遍历的模式,在客户规模较大时,循环本身的开销会占到总运行时间的大头
- 反复通过
DataFrame.append拼接子表,每次拼接都会触发全量数据内存拷贝,内存冗余度极高 - 手动排序、重排索引的逻辑存在大量可被pandas内置向量化能力覆盖的重复计算,原实现兼容pandas新版本时还会因为
append方法被弃用抛出警告
高效优化实现
完全依托pandas原生向量化分组能力,不需要写逐客户循环、不需要手动拼接数据、不需要额外调用reindex还原初始索引,单条逻辑即可1:1复现原函数的全部功能,在万行以上规模的数据场景下,运行效率比原实现提升1~2个数量级:
def incremental_id(data, datecol, id_col): data = data.copy() # 组内按日期升序生成从0起始的增量ID,与原数据索引完全对齐 data['Incremental_id'] = ( data.groupby(id_col)[datecol] .rank(method="first", ascending=True) .astype(int) - 1 ) return data
功能一致性说明
rank(method="first")的排序逻辑与原函数中按日期升序排的业务逻辑完全对齐:同组内按日期从小到大赋值增量ID,遇到同日期值时按行在原数据中的先后顺序排序,不会出现业务逻辑上的错位- 排名结果默认从1开始计数,减1后正好匹配原函数中
np.arange(子表行数)生成的从0起始的增量ID - 全程没有打乱原数据的行顺序,从根源上省去了原实现最后
reindex对齐初始索引的额外开销,也不需要反复拼接临时DataFrame,同时完全兼容pandas 2.0以上的新版本(原实现依赖的DataFrame.append方法已在新版本中被移除)
关于列表推导与lambda的选型说明
列表推导、lambda本质上还是逐元素/逐行的遍历逻辑,哪怕写法上替代了for循环,运行效率也远低于pandas底层用C实现的向量化算子。如果只是为了追求无循环的简洁写法,上述向量化实现的效率远高于硬凑出来的列表推导/lambda版本,同时代码可读性也更强。
内容的提问来源于stack exchange,提问作者Dhruv Sharma
相关产品推荐
相关产品推荐

