我正在尝试在字典中对已排序的元组实现快速查找;回答“元组(3,8)是否具有相关价值的问题,如果是,它是什么?”。让元组中的整数从下面绑定0,从上面绑定max_int。
我继续使用Python的dict,但发现它很慢。解决这个问题的另一种方法是创建一个包含max_int(通常为空)dicts的列表T,并为每个元组(3,8)设置T [3] [8] = value。 我虽然这正是Python用dicts做的bucket-hash方法,但后者在这里快了大约30倍(!)。
此外,它很难看(特别是因为我现在要实现3元组),所以我非常感谢这里的一些提示。
供参考,以下是我用来获取时间的代码:
import numpy as np
import time
# create a bunch of sorted tuples
num_tuples = 10
max_int = 100
a = np.random.rand(num_tuples,2) * max_int
a = a.astype(int)
for k in xrange(len(a)):
a[k] = np.sort(a[k])
# create dictionary with tuples as keys
d = {}
for t in a:
d[tuple(t)] = 42
print d
# do some lookups
m = 100000
start_time = time.time()
for k in xrange(m):
(3,8) in d.keys()
elapsed = time.time() - start_time
print elapsed
# now create the bucket-list structure mentioned above
t = [{} for k in xrange(max_int)]
for k in xrange(len(a)):
t[a[k][0]][a[k][1]] = 42
print t
# do some lookups
m = 10000
start_time = time.time()
for k in xrange(m):
8 in t[3].keys()
elapsed = time.time() - start_time
print elapsed
答案 0 :(得分:18)
以下是Python 2.7的精确计时结果:
>>> %timeit (3, 8) in d.keys() # Slow, indeed
100000 loops, best of 3: 9.58 us per loop
>>> %timeit 8 in t[3].keys() # Faster
1000000 loops, best of 3: 246 ns per loop
>>> %timeit (3, 8) in d # Even faster!
10000000 loops, best of 3: 117 ns per loop
>>> %timeit 8 in t[3] # Slightly slower
10000000 loops, best of 3: 127 ns per loop
它们表明标准(3, 8) in d
(无.keys()
列表构建)实际上比(不太常规)8 in t[3]
方法快一点,并且快两倍作为问题的相对较快8 in t[3].keys()
。这个.keys
/没有.keys
差异来自于(3, 8) in d.keys()
构建密钥的列表(在Python 2中)然后在此列表中查找(3, 8)
的事实,这是比在字典(3, 8)
的哈希表中查找d
要慢得多。
如评论中所述,时序结果与Python 3不同:Python 3的keys()
具有快速in
测试,因为keys()
返回键上的视图,因此in
运算符可以使用相应字典的哈希表。
原始问题的速度差异来自d.keys()
与t[3].keys()
相比构建相对较长的列表这一事实。
PS:%timeit
函数由优秀的IPython shell提供。原始程序可以通过IPython %run prog.py
执行。
答案 1 :(得分:3)
您正在测试不同的值。在字典版本中,有一个100,000个键的查找,而在bucket-list结构中,查找只有10,000个键。
除此之外,这段代码正在减慢速度:(3,8) in d.keys()
如果您刚刚编写(3,8) in d
,那么两个版本中的查找时间将非常相似,差异可以忽略不计。尝试这个修改过的测试,看看自己:
import numpy as np
import time
# create a bunch of sorted tuples
num_tuples = 10
max_int = 100
a = np.random.rand(num_tuples,2) * max_int
a = a.astype(int)
for k in xrange(len(a)):
a[k] = np.sort(a[k])
# create dictionary with tuples as keys
d = {}
for t in a:
d[tuple(t)] = 42
# do some lookups
m = 100000
start_time = time.time()
for k in xrange(m):
if (3,8) in d:
pass
elapsed = time.time() - start_time
print elapsed
# now create the bucket-list structure mentioned above
t = [{} for k in xrange(max_int)]
for k in xrange(len(a)):
t[a[k][0]][a[k][1]] = 42
# do some lookups
m = 100000
start_time = time.time()
for k in xrange(m):
if 8 in t[3]:
pass
elapsed = time.time() - start_time
print elapsed
观察到的行为的原因是(3,8) in d.keys()
和8 in t[3].keys()
每次都创建一个新的临时密钥列表,但第二个版本创建更短的列表。如果您只是使用了成语key in dictionary
,则不再创建临时列表,并且两种方法的性能开始相似。
我会使用第一个版本,更简单,更易于阅读和理解,并且惯用 - 如果使用得当,其性能与第二个版本一样好。
答案 2 :(得分:0)
比较set.seed(1)
n = 50
x = rpois(n, 2.2)
cdf = function(x,n)
{
v=c()
for(z in 1:max(x))
{
a = length(x[x<=z])/n
v = c(v, a)
}
plot(v,type="l", main="empirical cumulative distribution function", xlab="x", ylab="cumulative probability", xlim=c(0,6), ylim=c(0,1.0))
}
cdf(x, n)
与(a, b) in d
的速度有点奇怪,因为后者假定b in t[a]
必须存在。
无论如何,第一种方式应该总是更快。这两个版本都包含 a 和 b 。第一个是分配元组并对其进行散列的额外开销。但是,第二种方法是进行两次单独的字典查找。