Python的统计模块不是为速度,而是为精度
The built-in sum can lose accuracy when dealing with floats of wildly
differing magnitude. Consequently, the above naive mean fails this
“torture test”
assert mean([1e30, 1, 3, -1e30]) == 1
returning 0 instead of 1, a purely computational error of 100%.
Using math.fsum inside mean will make it more accurate with float
data, but it also has the side-effect of converting any arguments to
float even when unnecessary. E.g. we should expect the mean of a list
of Fractions to be a Fraction, not a float.
相反,如果我们看一下在这个模块中的_sum()的实现,方法的docstring seem to confirm that的第一行:
def _sum(data, start=0):
"""_sum(data [, start]) -> (type, sum, count)
Return a high-precision sum of the given numeric data as a fraction,
together with the type to be converted to and the count of items.
[...] """
所以,sum的统计实现,而不是一个简单的单线程调用Python的内置sum()函数,本身需要大约20行,其中有一个嵌套for循环。
这是因为statistics._sum选择保证它可能遇到的所有类型的数字的最大精度(即使它们彼此差别很大),而不是简单地强调速度。
因此,看起来正常的是,内置的和证明了一百倍更快。它的成本是一个低得多的精度在你碰巧用异国情调的数字。
其他选项
如果你需要在你的算法的优先级的速度,你应该看看Numpy相反,其实现在C的算法。
NumPy的平均值不如通过长时间统计的精确,但它实现(自2013年)一个routine based on pairwise summation这比天真的sum / len(更多的信息在链接)。
然而…
import numpy as np
import statistics
np_mean = np.mean([1e30, 1, 3, -1e30])
statistics_mean = statistics.mean([1e30, 1, 3, -1e30])
print('NumPy mean: {}'.format(np_mean))
print('Statistics mean: {}'.format(statistics_mean))
> NumPy mean: 0.0
> Statistics mean: 1.0