Python怎么查找列表中位数_中位数获取的多种高级数据结构解法
statistics.median 最快但限制多:仅支持数值型可索引序列,不接受None、字符串、迭代器或空列表;手写时sorted()性能差,nums.sort()改原列表,numpy.median需权衡依赖与精度。
用 statistics.median 最快,但要注意输入类型
Python 标准库的 statistics.median 是最直接的解法,它自动处理奇偶长度、排序和类型校验。但它不接受 None、字符串混入数字、或生成器——遇到就抛 TypeError: unsupported operand type(s) 或 StatisticsError。
- 只支持
list、tuple、range等可索引的序列,不能传map或filter返回的迭代器 - 元素必须全为数值(
int、float、Decimal),混入'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.nsmallest 或 numpy.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 再算,别依赖鸭子类型自动适配
中位数看着简单,但数据类型、缺失值、内存模型、精度要求这四点一叠,很容易在交接处出问题。特别是跨库传递数据时,别假设「方法名一样,行为就一样」。