我有时间序列数据,我目前存储在字典中,字典'keys'是datetime.datetime
个对象。有点像:
data[datetime.datetime(2012,5,14,15,28,2)]={'error':error,'flags':flags,'value':value}
我的问题是:在指定时间内找到最近两次(之前和之后)的最佳方法是什么?我需要这个函数尽可能快,因为它被调用(~10,000)在一个循环内部,在两个最近的点之间进行线性插值。
我目前有一种方法可以使用,因为它搜索了所有键(~50,000),所以需要花费很长的时间:
def findTime(time):
keys=data.keys()
bdt=10000000000000000000
adt=10000000000000000000
minKey=False
maxKey=False
for key in keys:
dt=(time-key).total_seconds()
if abs(dt)<bdt and dt>0:
bdt=abs(dt)
minKey=key
elif abs(dt)<adt and dt<0:
adt=abs(dt)
maxKey=key
return minKey,maxKey
我尝试使用bisect:
def findTime(time):
keys=data.keys()
l,r = bisect.bisect_left(time,keys), bisect.bisect_right(time,keys)
return l,r
不幸的是,这会产生错误:
TypeError: 'datetime.datetime' object does not support indexing
任何帮助都将不胜感激。
答案 0 :(得分:4)
bisect
函数将第一个参数作为排序数组(或列表,或者实际上是可以索引的任何内容)。 keys
是一个未排序的数组,你将它作为第二个参数传递。
这应该有效:
def findTime(time):
keys = sorted(data.keys())
return bisect.bisect_left(keys, time), bisect.bisect_right(keys, time)
尽管您应该保留已排序的副本,以便重复搜索但不会更改数据,而不是每次都重新排序。
答案 1 :(得分:3)
使用不同的密钥为你的dict做得好得多。
两个是显而易见的。
1)您可以将ISO 8601日期格式用作字符串。这基本上是YYYY-MM-DD
格式。您还可以使用YYYY-MM-DD:HH:MM:SS
格式。 ISO 8601的属性是词法排序,因此在排序的键列表中,只需在插入点的上方和下方取两个排序的键。
2)你可以使用日期的浮点表示,整数部分是偏离千年标记的一天,浮点数是当天的分数,然后很容易转换为HH:MM:SS。 Excel和Windows和Unix使用这种方法。
1)的例子:
>>> datetime.datetime.fromtimestamp(time.time()).isoformat()
'2012-05-14T13:55:22.142548' # a hashable, sortable dict key based on time
2)的例子:
>>> time.time() # That is days and fraction of day since 1/1/1970
1337028447.499273 # THAT is you dict key
>>> datetime.datetime.fromtimestamp(time.time()).timetuple()
time.struct_time(tm_year=2012, tm_mon=5, tm_mday=14, tm_hour=13, tm_min=52, tm_sec=13, tm_wday=0, tm_yday=135, tm_isdst=-1)
在任何一种情况下,Python都能够以毫秒为单位管理50,000个元素的数据结构。
根据需要将时间戳转换为日期时间对象。
答案 2 :(得分:1)
基于bisect
模块创建索引似乎是一个有价值的想法。但是,通过查看文档,您将看到bisect函数将排序列表作为第一个参数而不是第二个参数。
尝试:
keys=sorted(data.keys())
bisect.bisect_left(keys,time), bisect.bisect_right(keys,time)
此外,您可以尝试通过在keys
函数之外构建findTime
对象来优化代码。如果data
字典未通过findTime
调用序列进行修改,则只需支付排序列表的构造一次。