其实,使用Python计算中位数时,最直接的方法就是调用statistics.median()。但这个函数有一个“小脾气”:它不接受空列表,遇到None或非数字值也不会自动跳过。很多新手初次上手时,就被它抛出的“StatisticsError: no median for empty data”给整懵了。

一句话总结:statistics.median() 用起来很简单,但前提是你得把数据清洗干净,并想好空列表时的处理策略。
为什么 statistics.median() 会报错 “StatisticsError: no median for empty data”?
这个错误其实不是bug,而是刻意的设计:median() 要求输入的数据必须至少包含一个数值。它不会自作主张地返回0、None,也不会跳过空数据——而是直接抛出 StatisticsError 来提醒你:数据有问题,得由你自己决定如何处理。
看看哪些场景容易触发这个错误:
- 从数据库或CSV文件读取一列,结果这一列全是空的
- 对数据做了一系列过滤操作后,发现结果集为空
- 用户压根没有输入任何数据
处理方式也不只是简单加个 try/except 就完事。你需要明确业务逻辑:遇到空数据时,到底该返回什么?是 float('nan')、None,还是直接给个默认值?
另外提醒一点:statistics.median_low() 和 statistics.median_high() 这两个兄弟函数,对待空输入的态度也是一样——拒绝得干脆利落。
传入 list、tuple、map 或生成器时,行为一致吗?
基本上,只要传入的是一个可迭代对象,且里面的元素全是数字(int、float、Fraction、Decimal 都行),median() 都能处理。但有一个隐藏的坑:它内部会把整个可迭代对象先转成列表再排序。所以,如果你传一个巨大的生成器进去,内存可能会被瞬间吃光。
具体来看:
- 支持的情况:
statistics.median([1, 2, 3])、statistics.median((1.5, 2.5, 3.5))、statistics.median(map(int, ['1','2','3']))这些都没问题 - 不推荐的情况:
statistics.median(range(1000000))—— 这会让内存直接爆炸,因为内部调用了list() - 返回值类型:整数列表返回整数,浮点数列表返回浮点数。如果混合类型(比如
[1, 2.0]),Python 会按类型提升规则处理——通常结果是浮点数
如何安全地处理含 None、字符串或缺失值的数据?
这里要特别注意:statistics.median() 不会帮你做任何数据清洗。遇到 None 直接报 TypeError,遇到字符串(哪怕看起来像数字的 '1')也一样报错。
通常的做法是:
- 先过滤,再计算:用列表推导式把脏数据清洗干净。比如
[float(x) for x in data if x is not None and str(x).strip() != ''] - 封装一个安全函数:写一个
safe_median()函数,里面先过滤掉非数字和NaN,再计算中位数。如果过滤后列表为空,可以返回float('nan')或其他自定义值。 - 别跟
pandas.Series.median()搞混:pandas 的median()默认会跳过NaN,但statistics.median()不会。两者语义完全不同,混用很容易出现逻辑偏差。
说到底,中位数计算本身并不复杂。真正考验人的,是真实数据里那些永远存在的脏、空、类型混乱的问题。关键不在于“怎么调用函数”,而在于“怎么定义有效数据”。毕竟,漏掉一次空列表检查,可能就导致整个API返回500错误。
