Python中如何基于离散数据计算累积分布函数并查询分位值
离散概率分布、累积分布计算及分位值查询实现
不需要依赖小众第三方工具包,基于pandas、scipy即可快速实现需求。
基础准备:计算累积分布(CDF)
首先对结果值排序后,累加概率列即可得到累积分布:
import pandas as pd # 示例数据 data = {'Result': [1, 2, 4, 6], 'Occurrence': [2,3,4,1], 'Probability':[0.2,0.3,0.4,0.1]} df= pd.DataFrame(data) # 必须先按结果值升序排序,否则累积计算结果错误 df = df.sort_values('Result').reset_index(drop=True) # 计算累积概率 df['CDF'] = df['Probability'].cumsum()
计算完成后得到的分布表如下:
| Result | Occurrence | Probability | CDF |
|---|---|---|---|
| 1 | 2 | 0.2 | 0.2 |
| 2 | 3 | 0.3 | 0.5 |
| 4 | 4 | 0.4 | 0.9 |
| 6 | 1 | 0.1 | 1.0 |
其中Probability列是离散概率分布(PMF)值,CDF列是累积分布值,对应横轴为Result、纵轴为概率的绘图需求。
分位值查询:获取指定概率水平对应的结果值
离散分布的分位值规则为:找到最小的结果值x,使得x对应的累积概率大于等于目标概率水平,两种常用实现方式如下:
方式1:纯pandas实现(无额外依赖)
用pandas内置的merge_asof做近似匹配,不需要手动写循环,可批量查询多个概率水平:
def get_discrete_quantile(input_df, target_prob_list): """ 批量查询离散分布指定概率对应的结果值 参数: - input_df: 包含Result、Probability列的原始分布DataFrame - target_prob_list: 目标概率水平列表,如[0.5, 0.6, 0.8] """ # 临时表计算CDF,避免修改原数据 temp = input_df.sort_values('Result').reset_index(drop=True) temp['CDF'] = temp['Probability'].cumsum() # 构造查询表 query = pd.DataFrame({'target_prob': target_prob_list}) # 向前匹配:找到第一个CDF大于等于目标概率的行 res = pd.merge_asof( query, temp[['CDF', 'Result']], left_on='target_prob', right_on='CDF', direction='forward' ) return res # 调用示例 targets = [0.5, 0.6, 0.8] quantile_res = get_discrete_quantile(df, targets) print(quantile_res)
输出结果:
target_prob CDF Result 0 0.5 0.5 2 1 0.6 0.9 4 2 0.8 0.9 4
结果说明:
- 50%概率对应结果2,累积到结果2时概率刚好达到0.5
- 60%、80%概率对应结果4,因为结果2的累积概率仅为0.5,下一个结果4的累积概率达到0.9,覆盖0.5~0.9区间的所有概率水平
方式2:scipy统计接口实现
如果习惯使用标准统计库接口,可使用scipy.stats.rv_discrete构造离散分布对象,直接调用ppf(分位函数)查询:
from scipy import stats # 构造离散分布实例 dist = stats.rv_discrete(values=(df['Result'], df['Probability'])) # 直接传入目标概率列表查询 print(dist.ppf([0.5, 0.6, 0.8])) # 输出: [2. 4. 4.],和纯pandas实现结果完全一致
可选:分布可视化
用matplotlib可快速绘制双轴图同时展示概率分布和累积分布:
import matplotlib.pyplot as plt fig, ax1 = plt.subplots(figsize=(8,4)) # 绘制概率分布柱状图 ax1.bar(df['Result'], df['Probability'], color='#1f77b4', alpha=0.6, label='PMF 概率分布') ax1.set_xlabel('Result 结果值') ax1.set_ylabel('Probability 概率', color='#1f77b4') # 绘制累积分布阶梯图 ax2 = ax1.twinx() ax2.step(df['Result'], df['CDF'], color='#ff7f0e', where='post', linewidth=2, label='CDF 累积分布') ax2.set_ylabel('Cumulative Probability 累积概率', color='#ff7f0e') ax2.set_ylim(0, 1.05) fig.legend(loc='upper center', ncol=2) plt.show()
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

