在Python中创建700k项的字典?
我有一个名为在Python中创建700k项的字典?,python,dictionary,hash,performance,Python,Dictionary,Hash,Performance,我有一个名为Point的类,它的属性只有x\u坐标和y\u坐标浮动。我有大约700000个点对象,我想存储在字典中 字典的键是点对象,相应的值是区域对象,其中包含大约1000个点。基本上,键p属于值r,这意味着点对象属于特定区域对象 长话短说,这是我试图执行的原始循环: look_up_table = {} for region in all_regions_list: for point in region.points_list: look_up_table[poin
Point
的类,它的属性只有x\u坐标
和y\u坐标
浮动。我有大约700000个点对象,我想存储在字典中
字典的键是点
对象,相应的值是区域
对象,其中包含大约1000个点。基本上,键p
属于值r
,这意味着点对象属于特定区域对象
长话短说,这是我试图执行的原始循环:
look_up_table = {}
for region in all_regions_list:
for point in region.points_list:
look_up_table[point] = region
在所有区域中,大约有700000个点对象已加载到内存中。因此,代码中的第4行可能会执行700k次,字典将有700k(键,值)对
假设每个点对象占用1KB的内存(这是不可能的),超过700000个点将占用约680MB的内存。我有超过3GB的空闲内存。此外;这些点和区域对象已加载到内存中
然而,这些简单的4行需要永远完成,我已经等了大约2个小时,没有运气。。。只需一个小时就可以散列10k个对象
所以,我的问题是,我有没有做错什么?是否有另一种方法可以在内存中存储700k对象,并能够在O(1)时间内查找某个键
顺便说一下,下面是点
类的重写方法:
def __hash__(self, *args, **kwargs):
""" overriden hash method """
hashcode = 133
hashcode = hashcode * 23 + self.x_coordinate
hashcode = hashcode * 23 + self.y_coordinate
return hashcode
def __eq__(self, other):
""" overriden equals method """
if not other:
return False
else:
return self.__cmp__(other) == 0
def __cmp__(self, other):
""" overriden compare method """
if other is not None:
origin = Point(0.0, 0.0)
if self.distance_between(origin) < other.distance_between(origin):
return - 1
elif self.distance_between(origin) > other.distance_between(origin):
return 1
else:
return 0
def\uuuu散列(self,*args,**kwargs):
“”“重写哈希方法”“”
hashcode=133
hashcode=hashcode*23+self.x_坐标
hashcode=hashcode*23+self.y\u坐标
返回哈希码
定义(自身、其他):
“”“重写等于方法”“”
如果不是其他:
返回错误
其他:
返回self.\uuu cmp\uuuu(其他)=0
定义cmp(自身、其他):
“”“已重写比较方法”“”
如果“其他”不是“无”:
原点=点(0.0,0.0)
如果(原点)之间的自距离小于(原点)之间的其他距离:
返回-1
elif自身距离(原点)>其他距离(原点):
返回1
其他:
返回0
提前感谢…您的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。尝试完全删除该函数,看看默认哈希函数是否更好
另外,您的\uu cmp\uu
函数效率很低,因为每次比较它都会调用distance\u-between
四次。尝试为每个点
预计算该点与原点之间的距离,并将其存储在点
对象中。然后,\uuuu-cmp\uuuu
可以是这样的:
def __cmp__(self, other):
return other.distance_to_origin - self.distance_to_origin
为什么不使用一个简单的(x,y)
元组来表示您的积分呢?或者一个。它会快得多。您考虑过使用阵列吗?numpy单个元素是统一的,而不是具有单个Python对象的开销。速度更快,内存效率更高 代码中至少有一个错误——可能不会导致性能问题,但值得指出。有一个要求\uuuuu hash\uuuu()
方法必须满足以下条件:
唯一需要的属性是比较相等的对象具有相同的哈希值;建议以某种方式将对象组件的哈希值混合在一起(例如,使用异或),这些组件也在对象的比较中发挥作用
使用您的方法定义,两个比较相等的对象完全可能具有不同的哈希值。对该代码的注释:
由于您的方法有固定数量的参数(如def\uuu eq\uuuu(self,other):
),您不需要测试other
是否为None
,只有在有可选参数时才需要这样做
您的\uu\cmp\uu
方法可疑。您没有显示
之间的距离的定义,但暗示它是该点的距离;即,从x,y到原点0,0的距离。回想一下,第3,4点的欧几里德范数与第4,3点相同。即使点x=3和y=4与x=4和y=3是不同的点,它们是否确实意味着在程序逻辑中是相同的点
区域
类import random
import math
size=100
class Point(object):
def __init__(self,x=0.0,y=0.0):
self.x=x
self.y=y
def __hash__(self):
t=(self.x,self.y)
return hash(t)
def __eq__(self, other):
return self.__cmp__(other) == 0
def distance_to_origin(self):
return math.hypot(self.x,self.y)
def __cmp__(self, other):
return other.distance_to_origin() - self.distance_to_origin()
look_up_table = {}
for i in range(0,700):
for j in range(0,1000):
x=Point(random.uniform(-size,size),random.uniform(-size,size))
look_up_table[x]=i
print len(look_up_table), "hash points with ",size*2," range"
示例代码基于其组成部分的元组实现了一个更快的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
。在我的机器上,这本词典是在3或4秒内完成的
如上所述,您在\uuuu cmp\uuuu
上的逻辑(我刚才简化了)可能有错误:
x=Point(1.0,2.0)
y=Point(1.0,2.0)
z=Point(2.0,1.0)
a=Point(2.2,1.1)
print "x=y?", x==y # as expected...
print "x=a?", x==a # also
print "x=z?", x==z # is that what you expect?
即使点(1.0,2.0)=点(2.0,1.0)
因为它们与点(0,0)
的距离相同,散列(1.0,2.0)!=散列(2.0,1.0)
。结果是,将有两个对象将相同的哈希值与不同的对象进行比较 好吧,我是一个“迟到者”,所以:
这里使用的\uuuuuuuuuuuuuuuuuuuuuuuuuuuu散列
和\uuuuuuuuuuuueq
的问题已被很好地涵盖。我想说,命名的tuple在这里的表现非常出色。下一个最快的收益(主要基于大小)将是使用\uuuuuu插槽
。死givaway是指当您确定该点“仅”具有这两个属性时
根据实际使用模式,我可能会:
returnself.region
in Point)