You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:55:01