有没有比dict()更快的东西?

时间:2016-11-19 15:16:54

标签: python python-3.x numpy dictionary python-internals

我需要一种更快的方式来存储和访问大约3GB的k:v对。其中kstringinteger,而vnp.array(),可以是不同的形状。 有没有任何对象,比标准python dict在存储和访问这样的表时更快?例如,a pandas.DataFrame

到目前为止,我已经理解python dict是一个非常快速的哈希表实现,对于我的特定情况,还有什么比这更好的吗?

5 个答案:

答案 0 :(得分:32)

没有什么比这个任务的字典更快,这是因为它的索引甚至成员资格检查的复杂性大约是O(1)。

将项目保存在字典中后,您可以在固定时间内访问它们。也就是说,问题不在于索引过程。但是,通过对对象及其类型进行一些更改,您可以稍微加快进程。这可能会在引擎盖的操作中引起一些优化。例如,如果你的字符串(键)不是很大,你可以实习它们,以便在内存中兑现,而不是作为一个对象创建。如果字典中的键被中断,并且查找键被中断,则可以通过指针比较而不是字符串比较来进行键比较(在散列之后)。这使得访问对象的速度更快。 Python在sys模块中提供了intern()函数,您可以将其用于此目的。

  

在“interned”字符串表中输入字符串并返回实习字符串 - 字符串本身或副本。实习字符串对于字典查找 ...

获得一点性能非常有用

以下是一个例子:

In [49]: d = {'mystr{}'.format(i): i for i in range(30)}

In [50]: %timeit d['mystr25']
10000000 loops, best of 3: 46.9 ns per loop

In [51]: d = {sys.intern('mystr{}'.format(i)): i for i in range(30)}

In [52]: %timeit d['mystr25']
10000000 loops, best of 3: 38.8 ns per loop

答案 1 :(得分:2)

不,我认为没有比dict更快的东西。索引检查的时间复杂度为 O(1)

-------------------------------------------------------
Operation    |  Average Case  | Amortized Worst Case  |
-------------------------------------------------------
Copy[2]      |    O(n)        |       O(n)            | 
Get Item     |    O(1)        |       O(n)            | 
Set Item[1]  |    O(1)        |       O(n)            | 
Delete Item  |    O(1)        |       O(n)            | 
Iteration[2] |    O(n)        |       O(n)            | 
-------------------------------------------------------

PS https://wiki.python.org/moin/TimeComplexity

答案 2 :(得分:2)

人们会认为数组索引比哈希查找更快。

因此,如果我们可以将这些数据存储在一个 numpy 数组中,并假设键不是字符串而是数字,那会比 Python 和字典更快吗?

不幸的是不是,因为 NumPy 是针对向量操作进行了优化,而不是针对单个值的查找。 熊猫的情况更糟。 在此处查看实验:https://nbviewer.jupyter.org/github/annotation/text-fabric/blob/master/test/pandas/pandas.ipynb

另一个候选对象可能是数组模块中的 Python 数组。但这不适用于可变大小的值。 为了使这项工作正常进行,您可能需要将其包装成一些纯 python 代码,这将阻碍数组提供的所有时间性能提升。

所以,即使放宽了 OP 的要求,似乎仍然没有比字典更快的选择。

答案 3 :(得分:1)

一个numpy.array []和简单的dict = {}比较:

import numpy
from timeit import default_timer as timer

my_array = numpy.ones([400,400])

def read_out_array_values():
    cumsum = 0
    for i in range(400):
        for j in range(400):
            cumsum += my_array[i,j]


start = timer()
read_out_array_values()
end = timer()
print("Time for array calculations:" + str(end - start))


my_dict = {}
for i in range(400):
    for j in range(400):
        my_dict[i,j] = 1

def read_out_dict_values():
    cumsum = 0
    for i in range(400):
        for j in range(400):
            cumsum += my_dict[i,j]
    
start = timer()
read_out_dict_values()
end = timer()
print("Time for dict calculations:" + str(end - start))

打印:

Time for dict calculations:0.046898419999999996
Time for array calculations:0.07558204099999999
============= RESTART: C:/Users/user/Desktop/dict-vs-numpyarray.py =============
Time for array calculations:0.07849989000000002
Time for dict calculations:0.047769446000000104

答案 4 :(得分:-5)

如果您的密钥是字符串,您可以考虑将它们存储在像Trie这样的数据结构中。即使要从Trie存储和检索,您也需要O(N),其中N是密钥的最大长度。同样发生在哈希计算中,它计算密钥的哈希值。哈希用于查找和存储哈希表。我们经常不考虑散列时间或计算。

你可以给Trie一个镜头,它应该是几乎相同的性能,可能会更快一点(如果哈希值的计算方式不同,那么

HASH[i] = (HASH[i-1] + key[i-1]*256^i % BUCKET_SIZE ) % BUCKET_SIZE 
由于碰撞我们需要使用256 ^ i。

您可以尝试将它们存储在Trie中,看看它的表现如何。