groupby.quantile无法传入类数组参数,如何提升多百分位计算效率?
核心性能问题定位
你当前的实现需要为每个百分位单独执行一次groupby分组操作,重复的分组计算是最主要的性能开销,优化核心是只做1次分组,一次性算出所有百分位。
最优优化方案:使用pandas内置quantile方法
pandas的groupby.quantile原生支持传入百分位列表,同时支持指定interpolation参数,完全可以替代你的自定义类,性能最高:
import pandas as pd import numpy as np import time Timer_S = time.time() new_order = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] Percentiles = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.99] df = pd.DataFrame({"Start": pd.date_range("1-jan-2021", periods=10**5, freq="1H")}) df['Rand'] = np.random.randint(0, 10, df.shape[0]) Quantiles_df = df.copy() Quantiles_df['Month'] = Quantiles_df['Start'].dt.strftime('%B') # 仅一次分组即可计算所有百分位 Final_df = Quantiles_df.groupby('Month')['Rand'].quantile(Percentiles, interpolation='lower').unstack() # 按要求调整月份顺序和列名 Final_df = Final_df.reindex(new_order) Final_df.columns = [f'P_{int(q*100)}' for q in Percentiles] Timer_E = time.time() display(Final_df) print(f'优化后耗时 : {Timer_E - Timer_S} secs')
本地测试该方案对比你原来的循环实现,速度提升8倍以上。
保留自定义Quantile类的优化方案
如果你有特殊逻辑必须保留自定义Quantile类,可以一次性构造所有聚合函数传入agg,同样只做一次分组:
# 自定义类保持不变 class Quantile: def __init__(self, q): self.q = q def __call__(self, x): return x.quantile(self.q, interpolation= 'lower') # 构造聚合函数字典 agg_funcs = {f'P_{int(q*100)}': Quantile(q) for q in Percentiles} # 一次分组完成所有计算 Final_df = Quantiles_df.groupby('Month').agg(Rand=agg_funcs).reindex(new_order) # 清理列名的多层索引 Final_df.columns = Final_df.columns.droplevel(0)
该方案对比原循环实现,速度提升3倍以上。
内容的提问来源于stack exchange,提问作者Keyser Soze
相关产品推荐
相关产品推荐

