如何提升Python自定义Decile(分位数)函数的运行效率?
优化十分位(Decile)计算的高效方案
原代码的核心性能瓶颈是循环内重复执行筛选求和操作,时间复杂度为O(n²),在大数据集下会导致耗时急剧增加。以下是几种针对性的优化方案:
方案一:基于排序+累计和+二分查找的向量化实现
利用pandas和numpy的向量化操作替代Python循环,将时间复杂度降至O(n log n),大幅提升效率:
import pandas as pd import numpy as np # 计算总成交量 total_volume = df['total_mrk_vol'].sum() # 对成交量列排序,计算累计占比(累计成交量/总成交量) sorted_vol = df['total_mrk_vol'].sort_values() cumulative_ratio = sorted_vol.cumsum() / total_volume # 通过二分查找快速定位每个值对应的累计占比,计算十分位排名 # side='right'确保匹配所有<=当前值的元素,与原代码逻辑一致 decile_indices = df['total_mrk_vol'].searchsorted(sorted_vol, side='right') - 1 df['total_decile_rank'] = np.ceil(10 * cumulative_ratio.iloc[decile_indices]).astype(int)
优化逻辑说明
- 排序与累计和:仅需一次排序和累计求和操作,避免了原循环中每次都要遍历全表计算筛选和的重复劳动
- 二分查找:
searchsorted通过二分查找快速定位每个值在排序序列中的位置,单次查找时间复杂度为O(log n) - 向量化计算:numpy的
ceil和pandas的内置方法均基于底层C实现,比Python循环的执行效率高几个数量级
方案二:利用rank函数结合自定义分桶(简化版)
如果你的业务逻辑允许基于数据排名的数量占比计算十分位(而非累计成交量占比),可以直接使用pandas的rank函数:
# 按成交量降序排名,将排名分为10个分桶,得到十分位 df['total_decile_rank'] = df['total_mrk_vol'].rank(pct=True, ascending=False).apply(lambda x: np.ceil(x * 10)).astype(int)
注意:此方法与原代码逻辑有差异,原代码是基于累计成交量占比,此方法是基于数据项的排名占比,需根据业务需求选择。
额外优化建议
- 避免在循环内修改DataFrame:原代码每次循环都对
df['total_decile_rank']赋值,这会触发多次数据拷贝,应改为先构建完整序列再一次性赋值 - 优先使用numpy函数替代math模块:numpy的向量化函数比math的单值函数更适合处理批量数据
内容的提问来源于stack exchange,提问作者jwilson
相关产品推荐
相关产品推荐

