Indice de recherche du point le plus proche dans les tableaux numpy des coordonnées x et y

j'ai deux tableaux numpy 2d: x_array contient des informations de position dans la direction x, y_array contient des positions dans la direction Y.

j'ai alors une longue liste de x,y des points.

pour chaque point de la liste, je dois trouver l'index du tableau de l'emplacement (spécifié dans les tableaux) qui est le plus proche de ce point.

j'ai naïvement produit quelque code qui fonctionne, basé sur cette question: trouver valeur la plus proche dans le tableau de numpy

c'est à dire

import time
import numpy

def find_index_of_nearest_xy(y_array, x_array, y_point, x_point):
    distance = (y_array-y_point)**2 + (x_array-x_point)**2
    idy,idx = numpy.where(distance==distance.min())
    return idy[0],idx[0]

def do_all(y_array, x_array, points):
    store = []
    for i in xrange(points.shape[1]):
        store.append(find_index_of_nearest_xy(y_array,x_array,points[0,i],points[1,i]))
    return store


# Create some dummy data
y_array = numpy.random.random(10000).reshape(100,100)
x_array = numpy.random.random(10000).reshape(100,100)

points = numpy.random.random(10000).reshape(2,5000)

# Time how long it takes to run
start = time.time()
results = do_all(y_array, x_array, points)
end = time.time()
print 'Completed in: ',end-start

je fais cela sur un ensemble de données volumineux et voudrais vraiment d'accélérer un peu. Quelqu'un peut-il l'optimiser?

Merci.


mise à JOUR: SOLUTION suggestions suivantes par @silvado et @justin (ci-dessous)

# Shoe-horn existing data for entry into KDTree routines
combined_x_y_arrays = numpy.dstack([y_array.ravel(),x_array.ravel()])[0]
points_list = list(points.transpose())


def do_kdtree(combined_x_y_arrays,points):
    mytree = scipy.spatial.cKDTree(combined_x_y_arrays)
    dist, indexes = mytree.query(points)
    return indexes

start = time.time()
results2 = do_kdtree(combined_x_y_arrays,points_list)
end = time.time()
print 'Completed in: ',end-start

ce code ci-dessus accéléré mon code (recherche de 5000 points en 100x100 matrices) de 100 fois. Fait intéressant, en utilisant scipy.spatial.KDTree (au lieu de scipy.spatial.cKDTree) a donné des temps comparables à ma solution naïve, il est donc certainement intéressant d'utiliser la version cKDTree...

49
demandé sur Community 2012-05-30 18:39:27

3 réponses

scipy.spatial dispose également d'une mise en œuvre de l'arbre k-d: scipy.spatial.KDTree .

l'approche consiste généralement à utiliser d'abord les données ponctuelles pour construire un arbre k-D. La complexité de calcul est de l'ordre de N log N, où N est le nombre de points de données. Les requêtes de portée et les recherches de voisinage le plus proche peuvent alors être effectuées avec la complexité de log N. C'est beaucoup plus efficace que de simplement faire du vélo à travers tous les points (complexité N).

ainsi, si vous avez des questions répétées sur la portée ou le plus proche voisin, un arbre k-D est fortement recommandé.

31
répondu silvado 2012-05-30 15:03:48

voici un scipy.spatial.KDTree exemple

In [1]: from scipy import spatial

In [2]: import numpy as np

In [3]: A = np.random.random((10,2))*100

In [4]: A
Out[4]:
array([[ 68.83402637,  38.07632221],
       [ 76.84704074,  24.9395109 ],
       [ 16.26715795,  98.52763827],
       [ 70.99411985,  67.31740151],
       [ 71.72452181,  24.13516764],
       [ 17.22707611,  20.65425362],
       [ 43.85122458,  21.50624882],
       [ 76.71987125,  44.95031274],
       [ 63.77341073,  78.87417774],
       [  8.45828909,  30.18426696]])

In [5]: pt = [6, 30]  # <-- the point to find

In [6]: A[spatial.KDTree(A).query(pt)[1]] # <-- the nearest point 
Out[6]: array([  8.45828909,  30.18426696])

#how it works!
In [7]: distance,index = spatial.KDTree(A).query(pt)

In [8]: distance # <-- The distances to the nearest neighbors
Out[8]: 2.4651855048258393

In [9]: index # <-- The locations of the neighbors
Out[9]: 9

#then 
In [10]: A[index]
Out[10]: array([  8.45828909,  30.18426696])
37
répondu efirvida 2015-09-25 11:59:48

si vous pouvez masser vos données dans le bon format, une façon rapide d'aller est d'utiliser les méthodes dans scipy.spatial.distance :

http://docs.scipy.org/doc/scipy/reference/spatial.distance.html

en particulier pdist et cdist fournissent des moyens rapides pour calculer les distances par paires.

4
répondu JoshAdel 2012-05-30 15:00:54