如何在Python中快速计算一堆十进制数的模式?

时间:2018-07-24 23:30:41

标签: python

我正在使用scipy.stats.mode来计算数字列表的模式。当数字是一堆float(使用内置float)时,该模式的计算速度非常快,但是当数字是一堆decimal.Decimal时,运算速度会慢得多。计算一堆Decimal的模式的快速(或更快)方法是什么?

1 个答案:

答案 0 :(得分:1)

首先,Decimal本质上比float慢,因为所有逻辑都是在Python中以一点C加速实现的,而不是在CPU上的自定义电路中实现的。

此外,如果将它们放入NumPy数组中,则NumPy对Decimal类型一无所知,因此必须将它们存储为drtype=object,这意味着引用了普通的Python每个操作都必须拆箱的对象。相比之下,float值可以与dtype=float存储在一起,这意味着它们只是可以直接使用(甚至可以通过CPU矢量化一次处理多个值)的原始IEEE两倍。 >

所以,我希望它大约慢一个数量级。而且,当我进行快速测试时,它要花很长时间。


第二,scipy.stats.mode is inherently slow if you have a lot of unique elements

而且,即使您不这样做,它仍会为您可能不需要的其他功能做额外的工作。


无论如何,您无需进行任何数学运算即可计算模式,只需比较值是否相等即可。

在其他任何地方,我们都无法从NumPy中获得任何好处。

因此,更简单,功能更弱的非NumPy解决方案实际上可能会更快。


如果您实际上需要scipy.stats.mode的任何功能,那对您没有帮助。例如,如果存在相同的值,它可以返回多个结果。它给出了模式的计数以及模式;它知道如何跳过NaN值,而不仅仅是告诉您模式是NaN。等

如果您需要任何特殊功能,则可能要考虑根据heremode中构建一个find_repeats替代品。即使在公平的情况下,它的速度也大约是模式的5倍,并且在有很多独特的情况下不会退化。因此,即使将使用Decimal的成本提高了10倍,也仍然可以很快完成。


但是,如果您不需要它们?

  • statistics.mode(a)实际上比scipy.stats.mode稍微快一点,即使在公平情况下,甚至在浮点数数组中也是如此。而且,与其花费Decimal一样多,它所花费的时间也不是原来的10倍,而是花费了几乎相同的时间。
  • collections.Counter(a).most_common(1)仅比statistics.mode慢50%,并且再也不会因Decimal而变慢。

关键是,在一个似乎公平的测试上,两种明显的stdlib解决方案在scipy值上的性能都比Decimal高出约10倍或7倍。而且,如果我针对最差情况的scipy测试进行了测试,其中几乎所有值都是唯一的,则scipy.stats.mode会再次变慢大约10倍,而普通的Python解决方案根本不会变慢。

无论如何,对于这种情况,时间对输入数据的细节比对大多数情况更为敏感。因此,与其发布您确实想针对实际数据进行测试的警告(知道有一半的读者不愿意并且只是将我的基准视为有意义的),我将保留基准对自己说,并坚持认为您确实非常希望根据自己的实际数据进行测试。