web-dev-qa-db-fra.com

Trouver l'indice du point le plus proche dans des tableaux numpy de 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 points x, y.

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

J'ai naïvement produit du code qui fonctionne, basé sur cette question: Trouver la valeur la plus proche dans le tableau 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 grand ensemble de données et j'aimerais vraiment accélérer un peu. Quelqu'un peut-il optimiser cela?

Merci.


MISE À JOUR: SOLUTION suite aux suggestions de @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 a accéléré mon code (recherche de 5000 points dans des matrices 100x100) par 100 fois. Fait intéressant, l'utilisation de scipy.spatial.KDTree (au lieu de scipy.spatial.cKDTree) a donné un timing comparable à ma solution naïve, il vaut donc vraiment la peine d'utiliser la version cKDTree ...

62
Pete W

scipy.spatial a également une implémentation d'arborescence 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 plage et les recherches de voisins les plus proches peuvent alors être effectuées avec la complexité du log N. C'est beaucoup plus efficace que de simplement parcourir tous les points (complexité N).

Ainsi, si vous avez répété des requêtes de plage ou de voisin le plus proche, un arbre k-d est fortement recommandé.

41
silvado

Voici une 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])
50
efirvida

Si vous pouvez masser vos données dans le bon format, une solution rapide consiste à utiliser les méthodes de scipy.spatial.distance:

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

En particulier, pdist et cdist fournissent des moyens rapides de calculer des distances par paires.

5
JoshAdel