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

如何基于计数字典计算Q1、中位数和Q3(无第三方库)

问题

我有如下形式的计数字典:

{1:2, 2:1, 3:1}

需要从中计算Q1、中位数和Q3。奇数样本量的情况计算起来很简单,但偶数样本量的情况我始终处理不好。要求不使用numpy等第三方库实现。

示例:

counts = {
    "4": 1,
    "1": 2,
    "5": 1
}

期望结果:

results = {
    "q1": 1,
    "median": 2.5,
    "q3": 4,
}

我目前写了如下代码,但无法处理所有情况:

import math

def get_ratings_stats(counts):
    """This function will return min, q1, median, q3 and max value from list of ratings."""

    cumulative_sum = 0
    cumulative_dict = {}
    for key, value in sorted(counts.items()):
        cumulative_sum += value
        cumulative_dict[key] = cumulative_sum

    q1_index = math.floor(cumulative_sum * 0.25)
    q3_index = math.ceil(cumulative_sum * 0.75)
    median_index = cumulative_sum * 0.5

    q1, q3, median = None, None, None
    print('indexes: ', q1_index, median_index, q3_index)
    for key, sum in cumulative_dict.items():
        if not q1 and sum >= q1_index:
            q1 = key
        if not q3 and sum >= q3_index:
            q3 = key
        if not median and sum >= median_index:
            median = key
解决方案

你的代码核心问题在于索引计算逻辑不准确,且未处理分位数刚好落在两个数值之间的情况(比如示例中的中位数需要取相邻值的平均值),同时字符串类型的键会干扰数值计算。以下是修正后的完整代码:

import math

def get_ratings_stats(counts):
    """返回计数字典对应的最小值、Q1、中位数、Q3、最大值"""
    # 将键转换为数值并排序,确保处理顺序正确
    sorted_items = sorted((int(k), v) for k, v in counts.items())
    if not sorted_items:
        return {}  # 空字典直接返回
    
    total = sum(v for _, v in sorted_items)
    min_val = sorted_items[0][0]
    max_val = sorted_items[-1][0]

    # 构建累积计数列表,同时保存对应的数值
    cumulative = []
    current_sum = 0
    for val, cnt in sorted_items:
        current_sum += cnt
        cumulative.append((val, current_sum))

    # 定义获取分位数的辅助函数
    def get_quantile(percentile):
        index = total * percentile
        # 遍历累积列表,找到对应的位置
        for i, (val, cnt) in enumerate(cumulative):
            if cnt > index:
                # 索引为整数时,取当前值与前一个值的平均(存在前一个值的情况)
                if index.is_integer():
                    prev_val = cumulative[i-1][0] if i > 0 else val
                    return (prev_val + val) / 2
                else:
                    return val
            elif cnt == index:
                # 累积计数等于索引时,取当前值与下一个值的平均(存在下一个值的情况)
                next_val = cumulative[i+1][0] if i < len(cumulative)-1 else val
                return (val + next_val) / 2
        return max_val  # 兜底返回最大值

    # 计算各个分位数
    q1 = get_quantile(0.25)
    median = get_quantile(0.5)
    q3 = get_quantile(0.75)

    return {
        "min": min_val,
        "q1": q1,
        "median": median,
        "q3": q3,
        "max": max_val
    }

# 测试示例
counts = {
    "4": 1,
    "1": 2,
    "5": 1
}
print(get_ratings_stats(counts))
# 输出: {'min': 1, 'q1': 1, 'median': 2.5, 'q3': 4, 'max': 5}

关键修正说明:

  • 键类型转换:将字符串键转为整数,避免字符串排序错误(如"10"排在"2"前),同时支持数值计算。
  • 累积计数结构:同时保存数值和对应的累积计数,便于快速定位分位数位置。
  • 分位数逻辑优化:
    • 当索引为整数时,说明分位数落在两个元素之间,取相邻数值的平均值。
    • 当累积计数刚好等于索引时,取当前值与下一个值的平均值。
  • 辅助函数复用:把分位数提取逻辑封装成函数,减少重复代码,提升可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:01:00