我正在使用scipy.stats.mode
来计算数字列表的模式。当数字是一堆float
(使用内置float
)时,该模式的计算速度非常快,但是当数字是一堆decimal.Decimal
时,运算速度会慢得多。计算一堆Decimal
的模式的快速(或更快)方法是什么?
答案 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。等
如果您需要任何特殊功能,则可能要考虑根据here在mode
中构建一个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解决方案根本不会变慢。
无论如何,对于这种情况,时间对输入数据的细节比对大多数情况更为敏感。因此,与其发布您确实想针对实际数据进行测试的警告(知道有一半的读者不愿意并且只是将我的基准视为有意义的),我将保留基准对自己说,并坚持认为您确实非常希望根据自己的实际数据进行测试。