我正在创建一个迭代算法(蒙特卡罗方法)。 该算法在每次迭代时返回一个值,创建一个值流。
我需要分析这些值,并在说1000
返回的值为epsilon
时停止算法。
我决定实施它计算最后max
个值的min
和1000
值,然后使用此公式error
计算(max-min)/min
将其与epsilon
:error<=epsilon
进行比较。如果达到此条件,请停止迭代并返回结果。
第一个大胆的想法是使用list
和append
个新值,计算最后一个max
和min
值每次追加后的{1}}值。
然后我决定不再使用1000
最后一个值。所以我记得deque
。这是一个非常好的主意,因为在1000
对象的两端添加和删除的复杂性是deque
。但它没有解决每次迭代需要遍历所有最后1000个值来计算O(1)
和min
的问题。
然后我记得有heapq
module。它使数据保持在每时每刻高效返回最小数据的方式。但我需要最小和最大的。此外,我需要保留元素的顺序,以便我可以保留max
最后返回的算法元素,我不知道如何使用1000
实现它。
记住所有这些想法我决定在这里问:
如何最有效地解决此问题?
答案 0 :(得分:7)
如果您有空/愿意更改error
的定义,您可能需要考虑使用variance
代替(max-min)/min
。
你可以compute the variance incrementally。
是的,使用此方法,您不会从流中删除任何值 - 方差将取决于所有值。但那又怎么样?有了足够的值,前几个对方差无关紧要,当足够的值聚集在某个固定值附近时,平均值variance/n
的方差将变小。
因此,您可以选择在variance/n < epsilon
。
答案 1 :(得分:6)
作为@ unutbu优秀创意的改进,您可以考虑使用指数加权移动方差。它可以在每次观察O(1)
时间内计算,需要O(1)
空间,并且随着观察时间的延长,其优势在于自动降低观察者的体重。
以下文件具有相关公式:link。参见其中的等式(140) - (143)。
最后,您可能希望使用标准偏差而不是方差。它只是方差的平方根,并且具有与原始数据具有相同单位的优点。这样可以更容易地制定有意义的停止标准。
答案 2 :(得分:4)
numpy怎么样?
只是为了比较速度:
import numpy as np
a = range(1000)
b = np.arange(1000)
max(a) # 29.7us
b.max() # 7.29us
你可以无限地写这个数组:
i = 0
b = np.empty([1000]) + np.nan
your loop:
b[i % 1000] = value
i += 1
超过1000次迭代的值将被覆盖。您可以使用np.nanmin(b)
和np.nanmax(b)
获得最低/最高。
nan
背后的想法是你用1000纳秒初始化这个数组,然后你一个接一个地覆盖它们。 nanmin
和nanmax
方法忽略了这些nan。
答案 3 :(得分:3)
我担心我现在无法提供一个很好的Python答案,但我会给你一个你需要使用的数据结构的大纲:
将1000个项目保留在FIFO队列中。保持指向队列中最大和最小项的指针。如果其中一个离开队列,则在队列中搜索新的最大/最小值(根据您的数据计算的摊销成本)。如果新的最大/最小值进入队列,只需更新指针(O(1))。假设您的数据正在收敛,这应该可以正常工作。
答案 4 :(得分:1)
创建具有minvalue和maxvalue属性的deque子类。添加或删除条目时,将它们与当前的最小值和最大值进行比较 - 如果要删除的值是当前最小值或最大值,则只需重新扫描最小值/最大值的双端队列。添加时,只需将新值与当前最小值和最大值进行比较,然后进行相应更新。这将优化扫描您的双端队列的最小值/最大值。
答案 5 :(得分:1)
您可以使用两个fibonacci heaps。添加值在O(1)中,删除在O(log(n))中。在您的问题中,您已经建议使用heapq模块。我不确定它提供了什么样的堆,但是正常的堆也可以非常顺利地工作。
您只能从一个堆中提取最小值而不是最大值的问题可以通过保留两个堆来解决。由于我不知道heapq模块,你或者可以为它提供自己的比较函数,或者你可以使用-value
而不是value
作为第二堆的密钥。