为什么collections.deque比collections.defaultdict慢?

时间:2011-08-04 07:48:53

标签: python performance spell-checking deque defaultdict

请原谅我以这样一般的方式询问,因为我确信他们的表现取决于他们如何使用它们,但在我的情况下,collections.dequecollections.defaultdict慢得多,当我想要验证是否存在值。

我使用spelling correction from Peter Norvig来验证用户对一小组单词的输入。因为我没有使用带字频率的字典,所以我最初使用了一个简单的list而不是defaultdict,但只要我注意到单个字词查找,就用deque替换它大约25秒。

令人惊讶的是,这并不比使用list快,所以我回到使用defaultdict几乎立即返回结果。

有人可以向我解释这种性能差异吗?

提前致谢


PS :如果你们中的一个想要重现我所说的话,请在Norvig的剧本中更改以下几行。

-NWORDS = train(words(file('big.txt').read()))
+NWORDS = collections.deque(words(file('big.txt').read()))

-return max(candidates, key=NWORDS.get)
+return candidates

1 个答案:

答案 0 :(得分:10)

这三种数据结构不可互换,它们的用途非常不同,并且具有非常不同的特征:

  • 列表是动态数组,您可以使用它们按顺序存储项目以进行快速随机访问,用作堆栈(在末尾添加和删除)或只是存储某些内容,然后以相同的顺序迭代它。
  • Deques也是序列,仅用于在两端添加和删除元素,而不是随机访问或堆栈式增长。
  • 字典(提供默认值只是一个相对简单和方便的但是 - 对于这个问题 - 不相关的扩展)是哈希表,它们将全功能键(而不是索引)与值相关联,并提供对值的非常快速的访问通过密钥和(必要)非常快速地检查密钥存在。他们没有维持秩序,要求钥匙可以清洗,但是,你不能在不破蛋的情况下制作煎蛋。

所有这些属性都很重要,无论何时选择一个属性都要记住它们。在这种特殊情况下破坏你的脖子的是字典的最后一个属性和必须检查的可能更正的数量的组合。一些简单的组合应该得出这个代码为给定单词生成的编辑数量的具体公式,但是每个经常错误预测这些事情的人都会知道,即使对于普通单词,这个数字也会出乎意料地大。

对于这些编辑中的每个,都会检查edit in NWORDS以清除导致未知单词的编辑内容。在Norvig的程序中没有一点问题,因为in检查(密钥存在检查),如前所述,非常快。但是你用一个序列(一个双端队列)交换了字典!对于序列,in必须迭代整个序列并将每个项目与搜索的值进行比较(它可以在找到匹配时停止,但由于编辑最少的是知道位于双端队列开头的单词,它通常仍会搜索所有或大部分双端队列。由于有很多单词并且对每个生成的编辑进行了测试,因此您最终会花费99%的时间在一个序列中进行线性搜索,在该序列中您可以对字符串进行散列并比较一次(或最多 - 在碰撞的情况 - 几次)。

如果你不需要权重,你可以在概念上使用你从未看过的虚假值,并且仍然可以获得O(1)in检查的性能提升。实际上,你应该使用一个set,它使用几乎与字典相同的算法,只是切掉它存储值的部分(它实际上是首先实现的,我不知道它到底有多远两个分歧,因为集合在一个专用的,单独的C模块中重新实现。)