我开始学习来自C ++背景的Python。我正在寻找的是一种快速简便的方法,可以在2D(numpy)多维点数组(也是numpy数组)中找到某个多维查询点的最近(最近邻居)。我知道scipy有一棵k-d树,但我认为这不是我想要的。首先,我将更改2D数组中多维点的值。其次,2D阵列中每个点的位置(坐标)很重要,因为我也将改变它们的邻居。
我可以编写一个穿过2D数组的函数,测量查询点和数组中点之间的距离,同时跟踪最小的一个(使用scipy空间距离函数来测量距离)。是否有内置功能可以做到这一点?我试图尽可能避免在python中迭代数组。我还将有许多查询点,因此至少有两个“for循环” - 一个遍历查询点,每个查询循环迭代2D数组并找到最小距离。
感谢您的任何建议。
答案 0 :(得分:5)
如果简洁是你的目标,那么你可以做到这一点:
In [14]: X = scipy.randn(10,2)
In [15]: X
Out[15]:
array([[ 0.85831163, 1.45039761],
[ 0.91590236, -0.64937523],
[-1.19610431, -1.07731673],
[-0.48454195, 1.64276509],
[ 0.90944798, -0.42998205],
[-1.17765553, 0.20858178],
[-0.29433563, -0.8737285 ],
[ 0.5115424 , -0.50863231],
[-0.73882547, -0.52016481],
[-0.14366935, -0.96248649]])
In [16]: q = scipy.array([0.91, -0.43])
In [17]: scipy.argmin([scipy.inner(q-x,q-x) for x in X])
Out[17]: 4
如果您有多个查询点:
In [18]: Q = scipy.array([[0.91, -0.43], [-0.14, -0.96]])
In [19]: [scipy.argmin([scipy.inner(q-x,q-x) for x in X]) for q in Q]
Out[19]: [4, 9]
答案 1 :(得分:4)
广播对于这种事情非常有用。我不确定这是否是你需要的,但在这里我用广播来找到p(3个空间中的一个点)和X(3个空间中的10个点的集合)之间的位移。
import numpy as np
def closest(X, p):
disp = X - p
return np.argmin((disp*disp).sum(1))
X = np.random.random((10, 3))
p = np.random.random(3)
print X
#array([[ 0.68395953, 0.97882991, 0.68826511],
# [ 0.57938059, 0.24713904, 0.32822283],
# [ 0.06070267, 0.06561339, 0.62241713],
# [ 0.93734468, 0.73026772, 0.33755815],
# [ 0.29370809, 0.76298588, 0.68728743],
# [ 0.66248449, 0.6023311 , 0.76704199],
# [ 0.53490144, 0.96555923, 0.43994738],
# [ 0.23780428, 0.75525843, 0.46067472],
# [ 0.84240565, 0.82573202, 0.56029917],
# [ 0.66751884, 0.31561133, 0.19244683]])
print p
#array([ 0.587416 , 0.4181857, 0.2539029])
print closest(X, p)
#9
答案 2 :(得分:1)
您可以计算所有距离scipy.spatial.distance.cdist( X, Y )
或使用RTree获取动态数据:http://gispython.org/rtree/docs/class.html。
答案 3 :(得分:0)
为了更快地搜索和支持动态项目插入,您可以将二叉树用于2D项目,其中大于和小于运算符的距离是通过到参考点(0,0)的距离来定义的。
def dist(x1,x2):
return np.sqrt( (float(x1[0])-float(x2[0]))**2 +(float(x1[1])-float(x2[1]))**2 )
class Node(object):
def __init__(self, item=None,):
self.item = item
self.left = None
self.right = None
def __repr__(self):
return '{}'.format(self.item)
def _add(self, value, center):
new_node = Node(value)
if not self.item:
self.item = new_node
else:
vdist = dist(value,center)
idist = dist(self.item,center)
if vdist > idist:
self.right = self.right and self.right._add(value, center) or new_node
elif vdist < idist:
self.left = self.left and self.left._add(value, center) or new_node
else:
print("BSTs do not support repeated items.")
return self # this is necessary!!!
def _isLeaf(self):
return not self.right and not self.left
class BSTC(object):
def __init__(self, center=[0.0,0.0]):
self.root = None
self.count = 0
self.center = center
def add(self, value):
if not self.root:
self.root = Node(value)
else:
self.root._add(value,self.center)
self.count += 1
def __len__(self): return self.count
def closest(self, target):
gap = float("inf")
closest = float("inf")
curr = self.root
while curr:
if dist(curr.item,target) < gap:
gap = dist(curr.item, target)
closest = curr
if target == curr.item:
break
elif dist(target,self.center) < dist(curr.item,self.center):
curr = curr.left
else:
curr = curr.right
return closest.item, gap
import util
bst = util.BSTC()
print len(bst)
arr = [(23.2323,34.34535),(23.23,36.34535),(53.23,34.34535),(66.6666,11.11111)]
for i in range(len(arr)): bst.add(arr[i])
f = (11.111,22.2222)
print bst.closest(f)
print map(lambda x: util.dist(f,x), arr)