【问题标题】:Dictionary searching with datetime keys使用日期时间键进行字典搜索
【发布时间】:2012-05-14 19:53:18
【问题描述】:

我有当前存储在字典中的时间序列数据,其中字典“键”是 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

任何帮助将不胜感激。

【问题讨论】:

  • 我不确定您是否可以根据日期时间对象对字典进行排序,但您尝试过吗?然后你就可以为你正在查找的键分配一个索引,只需将索引加/减 1 即可找到最近的时间。
  • 你能把 datetime 日期转换成从某个时间开始的秒偏移量吗?然后你可以只使用浮点数或整数。
  • 您可以按日期时间对象对字典进行排序。问题是我想要的时间不一定是字典里的键
  • 我同意 drawk 你应该只使用时间戳而不是日期时间对象
  • @Cryptite:字典没有任何顺序,因此排序对它们没有意义。

标签: python dictionary indexing python-2.7


【解决方案1】:

bisect 函数的第一个参数是一个排序数组(或列表,或者实际上是任何可以被索引的东西)。 keys 是一个未排序的数组,您将它作为第二个参数传递。

这应该可行:

def findTime(time):
    keys = sorted(data.keys())
    return bisect.bisect_left(keys, time), bisect.bisect_right(keys, time)

尽管您应该保留已排序的副本以用于未更改数据的重复搜索,而不是每次都重新排序。

【讨论】:

  • 谢谢!像魅力一样工作!现在我的算法快了约 20 倍。
【解决方案2】:

你最好为你的 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 个元素的数据结构。

根据需要将时间戳转换为日期时间对象。

【讨论】:

    【解决方案3】:

    基于bisect 模块创建索引似乎是一个值得深入研究的想法。但是,通过查看文档,您会发现 bisect 函数将排序列表作为第一个参数,而不是第二个参数。

    试试:

    keys=sorted(data.keys())
    bisect.bisect_left(keys,time), bisect.bisect_right(keys,time)
    

    此外,您可以尝试通过在 findTime 函数之外构造 keys 对象来优化您的代码。如果您的data 字典没有通过您的findTime 调用序列进行修改,则您只需支付一次排序列表的构建费用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多