让b
成为具有某些值的词典:
b = {}
b[90, 1] = 100, b[90, 55] = 101, b[90, 127] = 102
b[70, 1] = 40, b[70, 45] = 41, b[70, 107] = 42
如何一次性填充dict
,其缺失值为最近邻居,例如0 <= i <= 127
,0 <= j <= 127
?
(它将在dict中提供16384个键,这样我的应用程序就可以了。)
作为一个例子,我想b[73, 40] = b[70, 45] = 41
,即2D平面中最近的邻居。
以下是我的尝试:
for i in range(127):
for j in range(127):
closest_key = min(b.keys(), key=lambda c: (c[0] - i) ** 2 + (c[1] - j) ** 2)
b[i, j] = b[closest_key]
但它很慢可能因为有127 * 127个循环,我们在所有元素上再循环一次以计算距离!
如何以更有效的方式使用最近邻居填充缺少值的字典?
答案 0 :(得分:2)
您正在b
内搜索最近的密钥。但b
不仅包含原始键,还包含每次迭代时输入的新键。只需检查初始键,就会更快,更正确:
initial_keys = set(b.keys())
for i in xrange(127):
for j in xrange(127):
if (i, j) not in initial_keys:
closest_key = min(
initial_keys, key=lambda c: (c[0] - i) ** 2 + (c[1] - j) ** 2
)
b[i, j] = b[closest_key]
这样算法的运行时间从O(k * n^2)
降至O(n^4)
,其中n
是维度大小,k
是初始键的数量。
编辑:
您可以使用numpy
来提高速度:
import numpy as np
s = set(b.keys())
x = np.array([k[0] for k in s])
y = np.array([k[1] for k in s])
for i in xrange(128):
for j in xrange(128):
if (i, j) not in s:
argmin = np.argmin((x - i) ** 2 + (y - j) ** 2)
b[i, j] = b[x[argmin], y[argmin]]
答案 1 :(得分:1)
字典绝对不适合此类用途 - 除非您对O(n)
复杂性感到满意(然后,使用列表会更清楚)。可以想象,a class of hashing functions可用于实施适当的&#34;字典&#34; - 但是python&#39; dict
绝对不能胜任这项任务。
如果您需要适当的性能,您需要使用其他数据结构。最简单的是K-d tree 。有一个实现inside scipy。
您可能需要查看专门针对nearest neighbor search
的维基百科文章当然,如果你反复查询相同的值,你可以使用字典作为缓存(如Raydel Miranda的回答)。但是将它用作缓存 - 而不是用于存储/查询实际数据!
答案 2 :(得分:0)
您可以尝试按需计算,并使用结果构建缓存。这种方法的优点是,如果你不需要使用某些点,它将永远无法计算。
完整示例:
b = {}
b[90, 1] = 100
b[90, 55] = 101
b[90, 127] = 102
b[70, 1] = 40
b[70, 45] = 41
b[70, 107] = 42
class NeighbourDist:
def __init__(self, source_dict):
# Original dict.
self.__source_dict = source_dict
# Dict used for cache.
self.__cache_dict = {}
def __calculate_distance(self, x0, x1, y0, y1):
""" Calculate distance beetwen two points. """
dx = x1 - x0
dy = y1 - y0
d = (dx**2 + dy**2)**0.5
return d
def __getitem__(self, key):
"""
Look for the key in the cached dict, if not has been calculated yet
then proceed to calculate it.
Return the result and store in __cache_dict.
"""
cached = self.__cache_dict.get(key)
if cached is not None:
return cached
else:
x0, y0 = key
min_n = 0
min_ = 1e100
for (x1, y1) in self.__source_dict.keys():
dist = self.__calculate_distance(x0, x1, y0, y1)
if min_ > dist:
min_ = dist
min_n = self.__source_dict[x1, y1]
self.__cache_dict[key] = min_n
return min_n
if '__main__' == __name__:
d = NeighbourDist(b)
print(d[73, 40]) # >>> 41
print(d[73, 40]) # >>> 41, Second time the result is obtained from the cached dict.