我有一个Python日期时间戳和一个大的dict(索引),其中键是时间戳,值是我感兴趣的其他一些信息。
我需要尽可能有效地在索引中找到最接近时间戳的日期时间(键)。
目前我正在做类似的事情:
for timestamp in timestamps:
closestTimestamp = min(index,key=lambda datetime : abs(timestamp - datetime))
哪个有效,但需要太长时间 - 我的索引字典有数百万个值,我正在进行数千次搜索。我对数据结构很灵活等等 - 时间戳大致是顺序的,所以我从第一个时间戳到最后一个时间戳进行迭代。同样,我加载到dict中的文本文件中的时间戳是顺序的。
非常感谢任何优化建议。
答案 0 :(得分:23)
字典不是为有效的近距离搜索而组织的。它们专为完全匹配而设计(使用hash table)。
你可能会更好地保持一个单独的,可快速搜索的有序结构。
一种简单的启动方式是使用bisect module进行快速O(log N)搜索,但使用较慢的O(n)插入:
def nearest(ts):
# Given a presorted list of timestamps: s = sorted(index)
i = bisect_left(s, ts)
return min(s[max(0, i-1): i+2], key=lambda t: abs(ts - t))
适用于非静态,动态更新的dicts的更复杂的方法是使用blist,它采用树结构进行快速O(log N)插入和查找。如果dict会随着时间的推移而改变,你只需要这个。
如果您希望继续使用基于字典的方法,请考虑使用附近时间戳对条目进行聚类的列表词典:
def get_closest_stamp(ts):
'Speed-up timestamp search by looking only at entries in the same hour'
hour = round_to_nearest_hour(ts)
cluster = daydict[hour] # return a list of entries
return min(cluster, key=lambda t: abs(ts - t))
注意,对于群集边界附近的精确结果,请在主群集和相邻群集中存储接近边界的时间戳。
答案 1 :(得分:3)
datetime对象彼此相似,因此请按如下所示制作键/值对的排序列表:
myPairs = list(dict.iteritems())
myPairs.sort()
对于每个元素myPairs[i]
,myPairs[i][0]
是datetime
键,myPairs[i][1]
是值。
您可以使用bisect_left
高效搜索此列表:
import bisect
i = bisect.bisect_left(myPairs, targetDatetime)
元素myPairs[i]
是日期时间最短不早于targetDatetime
的元素。但是先前的元素(如果有的话)可能会更接近targetDatetime
。或targetDatetime
可能比myPairs
中的任何时间晚。所以你需要检查:
if i > 0 and i == len(myPairs):
i -= 1
elif i > 0 and targetDatetime - myPairs[i-1][0] < myPairs[i][0]- targetDatetime:
i -= 1
答案 2 :(得分:2)
如果您的列表是真正排序的,而不仅仅是“大致顺序”,您可以使用二进制搜索。有关详细信息,请查看bisect
module documentation。