Python怎么查找列表中位数_中位数获取的多种高级数据结构解法

statistics.median 最快但限制多:仅支持数值型可索引序列,不接受None、字符串、迭代器或空列表;手写时sorted()性能差,nums.sort()改原列表,numpy.median需权衡依赖与精度。

statistics.median 最快,但要注意输入类型

Python 标准库的 statistics.median 是最直接的解法,它自动处理奇偶长度、排序和类型校验。但它不接受 None、字符串混入数字、或生成器——遇到就抛 TypeError: unsupported operand type(s)StatisticsError

  • 只支持 listtuplerange 等可索引的序列,不能传 mapfilter 返回的迭代器
  • 元素必须全为数值(intfloatDecimal),混入 '1' 字符串会报错
  • 空列表触发 StatisticsError: no median for empty data,得自己兜底

示例:

from statistics import median
median([3, 1, 4, 1, 5])  # → 3
median([2, 4])           # → 3.0(返回 float,即使输入是 int)

手写中位数逻辑时,sorted()list.sort() 性能差一倍

很多人直接 sorted(nums)[len(nums)//2],看起来简洁,但每次调用都新建列表、全量排序,时间复杂度 O(n log n),空间 O(n)。如果只是查一次还行;高频调用或数据量大(>10⁴ 元素),明显拖慢。

  • nums.sort() 原地排序再取索引,省掉一半内存分配,但会改原始列表——如果你后续还要用原顺序,这就埋雷
  • 真正想兼顾性能与安全?先 nums_copy = nums.copy()sort(),比 sorted() 快约 15%~20%,尤其在小列表(
  • 注意:len(nums)//2 对偶数长度只取下中位,要完整中位需手动算平均值,别漏了分支

示例:

def median_manual(nums):
    if not nums:
        raise ValueError("empty list")
    s = sorted(nums)
    n = len(s)
    if n % 2 == 1:
        return s[n//2]
    else:
        return (s[n//2 - 1] + s[n//2]) / 2

大数据量别硬排:用 heapq.nsmallestnumpy.median

当列表超 10⁵ 元素,或者你只需要中位数、不关心整个有序序列,全排序就是浪费。这时候两种替代路径更合理:

CEIFI

CEIFI提供国内外最新最全面的AI工具、资源和资讯

下载

  • heapq.nsmallest(k, nums) 可以在 O(n log k) 时间内拿到最小的 k 个数。对中位数,k ≈ n//2,实际性能不一定赢过 sorted,但内存稳定在 O(k),适合内存受限场景
  • numpy.median 底层用 C 实现,对 >10⁴ 数字数组快 3~5 倍,且自动处理 NaN(用 nan_policy='omit'),但引入 numpy 依赖,且把纯 Python 列表转成 np.array 有初始化开销
  • 注意:numpy.median 默认返回 float64,哪怕输入是 int32;如需保持整型精度,得手动 cast 或用 np.quantile(..., interpolation='lower')

示例:

import numpy as np
np.median([1, 2, 3, 4])  # → 2.5(float64)
# 不想转 float?得自己截断或用 int(np.median(...)),但可能丢精度

自定义类或 pandas Series 调用 .median() 时,行为不一致

看似统一的方法名,背后逻辑常被忽略:pandas.Series.median() 默认跳过 NaN,而 statistics.median 遇到 NaN 直接报错;自定义类若实现 __getitem____len__,但没重载 median,调用 statistics.median 仍会失败。

  • pandas 中 Series([1, 2, np.nan]).median()1.5;同数据喂给 statistics.median 就炸
  • 如果你封装了带单位的数值类(比如 Quantity),即使它支持比较和索引,statistics.median 仍可能因内部用 len() + __getitem__ + 排序逻辑失败,报 TypeError: '
  • 安全做法:显式转成 list 或 numpy array 再算,别依赖鸭子类型自动适配

中位数看着简单,但数据类型、缺失值、内存模型、精度要求这四点一叠,很容易在交接处出问题。特别是跨库传递数据时,别假设「方法名一样,行为就一样」。

相关推荐:

用ChatGPT写文档格式问题踩坑后总结的解法

做日常文档工作时,我习惯在kula ai聚合平台(leadhi.cn)上同时调用多个模型,横向对比它们的输出格式与质量,从而快速判断哪个模型更适合当前的格式场景。最近一个月,我大量使用chatgpt撰写技术文档、数据报告和方案材料,过程中在格式问题上踩了不少坑。本文只聚焦真实痛点与可落地的解决方案。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜...

DeepSeek处理嵌套JSON和复杂数据结构的技巧

DeepSeek不直接处理JSON,需代码兜底:先校验content是否为合法JSON字符串,再用try/except解析;递归提取时须同时处理dict和list;扁平化宜用点分路径并防key冲突;启用JSON模式前须确认模型支持。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜ DeepSeek 本身不直接“处理”JSON——它生成或理解J...
· AI · 261665

系统更新一直卡在“正在估算时间”?别傻等一晚上【最快解法】

若Windows更新卡在“正在估算剩余时间”,可依次尝试:一、重启Windows Update与BITS服务;二、清空SoftwareDistribution缓存;三、运行sfc /scannow和DISM修复系统;四、备份并恢复$GetCurrent\Media文件夹;五、使用MediaCreationTool离线升级。 如果您启动系统更新后,界面长时间停留在“正在估算剩余时间”而无任何进度变化...

如何在Python中为测试用例添加自定义标记_通过pytest.mark进行分类执行

pytest.mark 必须作为装饰器直接作用于测试函数或类,不可写在函数外部;可叠加多个标记,执行时用 -m "mark1 and mark2" 等布尔表达式筛选;未注册标记会触发警告,需在 pytest.ini 或 pyproject.toml 中声明以避免。 pytest.mark 能不能直接用在函数外面 不能。所有 pytest.mark 必须装饰在测试函数或类上,写在函数定义之外会报 S...
· Python · 98494

如何在Python中构建树状结构的递归生成器_使用yield from简化递归代码

yield from 在树遍历中省去了手动展开子生成器的繁琐与风险,自动处理委托调用、异常传播、StopIteration 捕获及协程方法转发,确保扁平化输出和行为一致性。 yield from 在树遍历中到底省了什么 直接说结论:yield from 不是语法糖,它把递归生成器的“委托调用”从手动循环 + yield 拆解成一条语句,避免了中间迭代器被提前耗尽、异常传播断裂、或 StopIter...
· Python · 306747

如何解决Python中的UnboundLocalError局部变量引用错误_使用global或nonlocal关键字声明

Python函数内同名变量报UnboundLocalError,因编译期将赋值变量标记为局部,读取在赋值前则出错;global用于模块级变量,nonlocal用于最近外层函数变量,二者不可混用且需提前声明。 为什么在函数里修改同名变量会报 UnboundLocalError Python 在编译函数时,只要看到某个变量在函数体内有赋值操作(哪怕只在 if 分支里),就会把它标记为局部变量。之后如果...
· Python · 158114

为什么Python脚本内存占用居高不下_使用objgraph与gc模块排查泄露

Python内存泄漏主因是对象被隐性持有而非未调gc.collect(),可用objgraph.show_growth()定位异常增长类型,再用gc.get_referrers()逆向追踪强引用源,并结合RSS监控与gc调试确认真实泄漏。 Python 脚本内存持续上涨,大概率不是“没调 gc.collect()”,而是对象根本没被识别为可回收——比如被全局容器悄悄持有、含 __del__ 的循环...
· Python · 244661

如何在Python Flask中集成Click命令行工具_使用app.cli.command

app.cli.command命令不出现的主因是Flask实例未完成初始化或注册时机过早;需确保在create_app()返回后注册,且装饰器顺序为@app.cli.command在上、@click.option等在下,同时避免顶层导入时执行注册。 为什么 app.cli.command 注册的命令不出现? 最常见原因是 Flask 应用实例未正确初始化 CLI 上下文,或者命令注册时机早于 ap...
· Python · 149248