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

如何在NumPy中基于汇总(观测值、响应数)数据计算中位数与百分位数

基于汇总统计数据计算中位数与百分位数

刚好碰到过类似的需求,咱们一步步来解决这个问题——不用展开原始数据,直接从[观测值, 响应次数]的汇总数据里算出和原始数据一致的中位数、百分位数结果。

先回顾原始数据的常规计算方式

percentile和median方法通常直接作用在原始未处理数据上,示例代码如下:

import numpy as np

raw_data = [1,1,1,1,2,3,4,4,5,5]  # 原始观测列表
a = np.array(raw_data)
print(np.median(a))          # 输出中位数:2
print(np.percentile(a, 50))  # 输出50分位数(和中位数结果一致):2

核心问题:用汇总数据实现相同计算

现在我们只有汇总后的统计数据:

summarised_data = [[1,4],[2,1],[3,1],[4,2],[5,2]]  # 结构:[[观测值, 出现次数], ...]

核心思路是通过累计计数定位目标位置,完全不需要展开原始数据。

方法1:纯Python手动实现

这种方式不用依赖任何库,逻辑清晰易懂:

summarised_data = [[1,4],[2,1],[3,1],[4,2],[5,2]]

# 拆分观测值和对应出现次数
values, counts = zip(*summarised_data)
# 计算累计出现次数
cumulative_counts = []
total_observations = 0
for cnt in counts:
    total_observations += cnt
    cumulative_counts.append(total_observations)

# 计算中位数对应的位置
if total_observations % 2 == 1:
    median_position = (total_observations + 1) // 2
else:
    median_position = total_observations // 2

# 定位中位数对应的观测值
median = None
for val, cum_cnt in zip(values, cumulative_counts):
    if cum_cnt >= median_position:
        median = val
        break

print(median)  # 输出:2,和原始数据计算结果一致

如果要计算任意百分位数(比如75分位数),可以封装成通用函数:

def calculate_percentile(summarised_data, percentile):
    values, counts = zip(*summarised_data)
    cumulative_counts = []
    total_obs = 0
    for cnt in counts:
        total_obs += cnt
        cumulative_counts.append(total_obs)
    # 计算百分位数对应的位置
    target_pos = (total_obs - 1) * percentile / 100
    # 找到对应区间的观测值
    for idx, cum_cnt in enumerate(cumulative_counts):
        if cum_cnt > target_pos:
            if target_pos.is_integer():
                return values[int(target_pos)]
            return values[idx]
    return values[-1]

# 验证50分位数(中位数)
print(calculate_percentile(summarised_data, 50))  # 输出:2
# 计算75分位数
print(calculate_percentile(summarised_data, 75))  # 输出:4,和原始数据的np.percentile(a,75)结果一致

方法2:用Numpy简化实现

如果习惯用Numpy,可以利用其数组操作快速实现:

import numpy as np

summarised_data = np.array([[1,4],[2,1],[3,1],[4,2],[5,2]])
values = summarised_data[:, 0]
counts = summarised_data[:, 1]

# 计算累计次数
cumulative_counts = np.cumsum(counts)
total_obs = cumulative_counts[-1]

# 定位中位数
median_pos = (total_obs - 1) * 0.5
median_idx = np.argmax(cumulative_counts > median_pos)
median = values[median_idx]
print(median)  # 输出:2

# 封装成通用百分位数计算函数
def np_calculate_percentile(summarised_data, percentile):
    values = summarised_data[:, 0]
    counts = summarised_data[:, 1]
    cumulative_counts = np.cumsum(counts)
    total_obs = cumulative_counts[-1]
    target_pos = (total_obs - 1) * percentile / 100
    idx = np.argmax(cumulative_counts > target_pos)
    return values[idx]

# 验证结果
print(np_calculate_percentile(summarised_data, 50))  # 2
print(np_calculate_percentile(summarised_data, 75))  # 4

内容的提问来源于stack exchange,提问作者Greg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:40:33