Python 在大小为>;的移动窗口中跟踪前n个值;N

Python 在大小为>;的移动窗口中跟踪前n个值;N,python,stack,queue,Python,Stack,Queue,假设我们有一个每分钟输入一次的数据流,我们希望在前10分钟内保持前5个值的运行轨迹。直观地说,应该有一些队列解决方案,但我正在努力寻找一种优雅的方法,因为一个元素可以出于两种不同的原因弹出(它看起来是11分钟前的位置,或者您不想实现队列,因为一旦您需要将元素从顶部移除,队列的便利性就会消失(与小于元素的情况一样)。下面是一个自定义类实现,它可以满足您的要求——诀窍是在添加值之前检查列表的值。这非常简单,但我希望它能让您了解: 从datetime导入datetime,timedelta 类TopL

假设我们有一个每分钟输入一次的数据流,我们希望在前10分钟内保持前5个值的运行轨迹。直观地说,应该有一些队列解决方案,但我正在努力寻找一种优雅的方法,因为一个元素可以出于两种不同的原因弹出(它看起来是11分钟前的位置,或者您不想实现队列,因为一旦您需要将元素从顶部移除,队列的便利性就会消失(与小于元素的情况一样)。下面是一个自定义类实现,它可以满足您的要求——诀窍是在添加值之前检查列表的值。这非常简单,但我希望它能让您了解:

从datetime导入datetime,timedelta
类TopLatestN():
定义初始化(self,最大大小:int=5,时间范围:int=10):
self.\uuu值=[]
self.times=[]#添加项目的匹配时间队列
self.max\u size=max\u size
self.timeframe\u m=timeframe\u m
def附加值(自身,值):
#删除太旧的值
自我检查次数()
如果len(self.\u值)=当前时间)
#替换所有时间的值
self.\uuu值=[val代表i,如果保留[i]],枚举中的val(self.\uu值)
self.times=[i的时间,如果保留[i],则枚举中的时间(self.times)]
定义检查值(自身、值):
#获取索引以存储足够大的值,否则返回None
如果有(自身值中val的值>val):
返回自身值。索引(最小值(自身值))#替换最小值
一无所获

不要忽略一件简单的事情-你可能会惊讶于它的工作原理。你有两个顺序,所以要按排序顺序维护两个序列,
按时间排序,
按值排序,
按值排序。在每个序列中存储两个元组
(值,时间戳)
对。当然,你需要保持它们的同步

由于
byvalue
始终按照按值排序的顺序进行维护,因此您可以随时查看顶部
n
、底部
n
、中间
n
,或任何其他您想要的顺序统计信息

假设您的时间戳(无论对您意味着什么)只会随着时间的推移而增加,那么按时间“排序”是很简单的:使用
collections.deque
并将新记录推到一端(例如,右侧),然后从另一端丢弃。使用
byvalue
的简单列表。要使旧记录过期,则:

oldest_to_retain = whatever form of timestamp you use
while bytime and bytime[0][1] < oldest_to_retain:
    t = bytime.popleft() # discard expired record
    # and remove it from the other seq too
    i = bisect.bisect_left(byvalue, t)
    assert byvalue[i] == t
    del byvalue[i]
(其他语句具有
O(1)
O(log(N))
行为。)

有了更多的经验,他们就克服了这一点;-)这些都是“以C的速度”发生的,除非
byvalue
增长到数百个元素,否则它通常比花哨的树结构更快,更节省空间,即使它们是用优化的C编码的


如果
byvalue
确实变大了,很容易将
byvalue
切换为使用广泛使用的
SortedList
。那么没有比关于
O(log(N))更糟糕的语句了
。您的代码部分仍然简单、灵活、易于推理。

将数据放入Pandas数据框,然后在前10分钟内访问5个最大值。
t = (the_new_value, current_timestamp)
assert not bytime or bytime[-1][1] <= current_timestamp
bytime.append(t)
bisect.insort(byvalue, t)
del byvalue[i]
bisect.insort(byvalue, t)