. , , .
n- :
class NearestDict(dict):
def __init__(self, ndims):
super(NearestDict, self).__init__()
self.ndims = ndims
def __setitem__(self, key, val):
if not isinstance(key, tuple): key = (key,)
if len(key) != self.ndims: raise KeyError("key must be %d dimensions" % self.ndims)
super(NearestDict, self).__setitem__(key, val)
@staticmethod
def __dist(ka, kb):
assert len(ka) == len(kb)
return sum((ea-eb)**2 for (ea, eb) in zip(ka, kb))
def nearest_key(self, key):
if not isinstance(key, tuple): key = (key,)
nk = min((k for k in self), key=lambda k: NearestDict.__dist(key, k))
return nk
def __missing__(self, key):
if not isinstance(key, tuple): key = (key,)
if len(key) != self.ndims: raise KeyError("key must be %d dimensions" % self.ndims)
return self[self.nearest_key(key)]
:
a = NearestDict(1)
a[1] = 100
a[55] = 101
a[127] = 102
print a[20]
print a[58]
print a[167]
print a.nearest_key(20)
print a.nearest_key(58)
print a.nearest_key(127)
b = NearestDict(2)
b[90, 1] = 100
b[90, 55] = 101
b[90, 127] = 102
b[70, 1] = 40
b[70, 45] = 41
b[70, 107] = 42
print b[73, 40]
print b.nearest_key((73,40))
, , , . , . , , .
Edit:
, Kasra, , , scipy cKDTree:
, regenOnAdd, () KDTree , () :
from scipy.spatial import cKDTree
class KDDict(dict):
def __init__(self, ndims, regenOnAdd=False):
super(KDDict, self).__init__()
self.ndims = ndims
self.regenOnAdd = regenOnAdd
self.__keys = []
self.__tree = None
self.__stale = False
def __setitem__(self, key, val):
if not isinstance(key, tuple): key = (key,)
if len(key) != self.ndims: raise KeyError("key must be %d dimensions" % self.ndims)
self.__keys.append(key)
self.__stale = True
if self.regenOnAdd: self.regenTree()
super(KDDict, self).__setitem__(key, val)
def regenTree(self):
self.__tree = cKDTree(self.__keys)
self.__stale = False
def nearest_key(self, key):
if not isinstance(key, tuple): key = (key,)
if self.__stale: self.regenTree()
_, idx = self.__tree.query(key, 1)
return self.__keys[idx]
def __missing__(self, key):
if not isinstance(key, tuple): key = (key,)
if len(key) != self.ndims: raise KeyError("key must be %d dimensions" % self.ndims)
return self[self.nearest_key(key)]
.
(NearestDict, KDDict(True) (regen on insert) KDDict(False) (defer regen)), .
3 . , :
- : 5 . (
timeit.repeat - 3). - : 0 <= x < 1000
- :. . 10000 .
4- 1000 .
{'NDIMS': 4, 'NITER': 5, 'NELEMS': 1000, 'NFINDS': 10000, 'DIM_LB': 0, 'DIM_UB': 1000, 'SCORE_MUL': 100}
insert::NearestDict 0.125
insert::KDDict(regen) 35.957
insert::KDDict(defer) 0.174
search::NearestDict 2636.965
search::KDDict(regen) 49.965
search::KDDict(defer) 51.880
4- 100 . , , .
{'NDIMS': 4, 'NITER': 5, 'NELEMS': 100, 'NFINDS': 10000, 'DIM_LB': 0, 'DIM_UB': 1000, 'SCORE_MUL': 100}
insert::NearestDict 0.013
insert::KDDict(regen) 0.629
insert::KDDict(defer) 0.018
search::NearestDict 247.920
search::KDDict(regen) 44.523
search::KDDict(defer) 44.718
100 (, ), 12 . , , .
{'NDIMS': 12, 'NITER': 5, 'NELEMS': 100, 'NFINDS': 10000, 'DIM_LB': 0, 'DIM_UB': 1000, 'SCORE_MUL': 100}
insert::NearestDict 0.013
insert::KDDict(regen) 0.722
insert::KDDict(defer) 0.017
search::NearestDict 405.092
search::KDDict(regen) 49.046
search::KDDict(defer) 50.601
KDDict (KDDict(True)) ( ), ( ). - NearestDict KDDict(False), KDDict
KDDict .
KDDict , NearestDict. - .
KDDict , NearestDict.
/, NearestDict , KDDict. 100 1000 NearestDict 9,64x, KDDict 0,16x.
, NearestDict , KDDict. 4 12 NearestDict 0,64x, KDDict 0,13x.
, scipy toolkit, KDDict.