Python分位数函数循环实现异常问题求助
Pandas循环生成分位数函数列表结果异常的解决方法
问题描述
尝试计算从percentile(0.05)到percentile(0.95)、步长0.05的分位数时,发现循环生成函数列表的方式结果异常,以下用0.05和0.85分位数举例:
正常实现(显式定义函数列表)
显式定义lambda函数列表时,分组聚合结果正确:
quantile_funcs = [lambda x : x.quantile(0.05), lambda x : x.quantile(0.85)] data = {'group':['A', 'B', 'A', 'A', 'B', 'B', 'B', 'A', 'A'], 'col1':[1, 3, 3, 5, 4, 6, 7, 7, 8]} df = pd.DataFrame(data) df['col2']=df['col1']+1 df_sum = df.groupby(['group']).agg([*quantile_funcs, "count", 'mean']) df_sum.columns = ['c1_P5', 'c1_p85', 'c1_ct', 'c1_mean', 'c2_P5', 'c2_p85', 'c2_ct', 'c2_mean'] print(df_sum)
异常实现(循环生成函数列表)
通过列表推导式循环生成lambda函数时,所有函数都使用了列表中最后一个分位数值(0.85),导致结果不符合预期:
percentiles = [0.05, 0.85] quantile_funcs = [lambda x: x.quantile(p) for p in percentiles] data = {'group':['A', 'B', 'A', 'A', 'B', 'B', 'B', 'A', 'A'], 'col1':[1, 3, 3, 5, 4, 6, 7, 7, 8]} df = pd.DataFrame(data) df['col2']=df['col1']+1 df_sum = df.groupby(['group']).agg([*quantile_funcs, "count", 'mean']) df_sum.columns = ['c1_P5', 'c1_p85', 'c1_ct', 'c1_mean', 'c2_P5', 'c2_p85', 'c2_ct', 'c2_mean'] print(df_sum)
问题原因
这是Python闭包的延迟绑定特性导致的:lambda函数中的变量p不会在定义时立即绑定当前循环值,而是在函数被调用时才去查找p的当前值。当列表推导式执行完成后,p最终指向列表的最后一个元素,所以所有lambda函数调用时都会使用这个值。
解决方法
方法1:使用默认参数绑定当前值
在lambda函数中添加默认参数,强制在定义时绑定当前循环的p值:
percentiles = [0.05, 0.85] quantile_funcs = [lambda x, p=p: x.quantile(p) for p in percentiles]
默认参数会在函数定义时求值并绑定,这样每个lambda都会持有各自对应的分位数值。
方法2:使用functools.partial创建绑定函数
通过functools.partial预先固定quantile方法的q参数,避免闭包延迟绑定问题:
from functools import partial percentiles = [0.05, 0.85] # 简洁写法:直接绑定pd.Series.quantile的q参数 quantile_funcs = [partial(pd.Series.quantile, q=p) for p in percentiles]
方法3:直接使用Pandas原生的分位数聚合方式
Pandas的agg方法支持直接传入带命名的聚合规则,无需手动生成函数,更简洁且不易出错:
percentiles = [0.05, 0.85] # 动态生成每个列的聚合规则 agg_rules = { col: [(f'P{int(p*100)}', lambda x, p=p: x.quantile(p)) for p in percentiles] + ['count', 'mean'] for col in ['col1', 'col2'] } df_sum = df.groupby(['group']).agg(agg_rules) # 展平多层列名 df_sum.columns = [f'{col}_{stat}' for col, stat in df_sum.columns] print(df_sum)
内容的提问来源于stack exchange,提问作者sguo
相关产品推荐
相关产品推荐

