web-dev-qa-db-fra.com

Calcul efficace de la distance entre N points et une référence en numpy/scipy

Je viens de commencer à utiliser scipy/numpy. J'ai un tableau 100000 * 3, chaque ligne est une coordonnée et un point central 1 * 3. Je veux calculer la distance pour chaque ligne du tableau au centre et les stocker dans un autre tableau. Quel est le moyen le plus efficace de le faire?

18
D. Huang

Je voudrais jeter un oeil à scipy.spatial.distance.cdist:

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

import numpy as np
import scipy

a = np.random.normal(size=(10,3))
b = np.random.normal(size=(1,3))

dist = scipy.spatial.distance.cdist(a,b) # pick the appropriate distance metric 

dist pour la métrique distante par défaut est équivalent à:

np.sqrt(np.sum((a-b)**2,axis=1))  

bien que cdist soit beaucoup plus efficace pour les baies de grande taille (sur ma machine, pour votre problème de taille, cdist est plus rapide d'un facteur environ 35 fois).

26
JoshAdel

Je voudrais utiliser la mise en œuvre de Sklearn de la distance euclidienne. L'avantage est l'utilisation de l'expression la plus efficace en utilisant la multiplication Matrix:

dist(x, y) = sqrt(dot(x, x) - 2 * dot(x, y) + dot(y, y)

Un script simple ressemblerait à ceci:

import numpy as np

x = np.random.Rand(1000, 3)
y = np.random.Rand(1000, 3)

dist = np.sqrt(np.dot(x, x)) - (dot(x, y) + dot(x, y)) + dot(y, y)

Les avantages de cette approche ont été décrits avec précision dans la documentation de sklearn: http://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.euclidean_distances.html#sklearn.metrics .pairwise.euclidean_distances

J'utilise cette approche pour traiter des données volumineuses volumineuses (10000, 10000) avec quelques modifications mineures, telles que l'utilisation de la fonction np.einsum.

5
lemitech

Vous pouvez également utiliser le développement de la norme (similaire aux identités remarquables). C'est probablement le moyen le plus efficace de calculer la distance d'une matrice de points.

Voici un extrait de code que j'ai utilisé à l'origine pour une implémentation de k-Nearest-Neighbours, dans Octave, mais vous pouvez facilement l'adapter à numpy puisqu'il utilise uniquement des multiplications de matrice (l'équivalent est numpy.dot ()):

% Computing the euclidian distance between each known point (Xapp) and unknown points (Xtest)
% Note: we use the development of the norm just like a remarkable identity:
% ||x1 - x2||^2 = ||x1||^2 + ||x2||^2 - 2*<x1,x2>
[napp, d] = size(Xapp);
[ntest, d] = size(Xtest);

A = sum(Xapp.^2, 2);
A = repmat(A, 1, ntest);

B = sum(Xtest.^2, 2);
B = repmat(B', napp, 1);

C = Xapp*Xtest';

dist = A+B-2.*C;
1
gaborous

Vous devrez peut-être spécifier de manière plus détaillée la fonction de distance qui vous intéresse, mais voici une implémentation très simple (et efficace) de Squared Euclidean Distance basée sur inner product (qui peut évidemment être généralisée, de manière simple, autre type de mesure de distance):

In []: P, c= randn(5, 3), randn(1, 3)
In []: dot(((P- c)** 2), ones(3))
Out[]: array([  8.80512,   4.61693,   2.6002,   3.3293,  12.41800])

P sont vos points et c est le centre.

0
eat
#is it true, to find the biggest distance between the points in surface?

from math import sqrt

n = int(input( "enter the range : "))
x = list(map(float,input("type x coordinates: ").split()))
y = list(map(float,input("type y coordinates: ").split()))
maxdis = 0  
for i in range(n):
    for j in range(n):
        print(i, j, x[i], x[j], y[i], y[j])
        dist = sqrt((x[j]-x[i])**2+(y[j]-y[i])**2)
        if maxdis < dist:

            maxdis = dist
print(" maximum distance is : {:5g}".format(maxdis))
0
Mohammad Feroz

Cela pourrait ne pas répondre directement à votre question, mais si vous êtes après toutes les permutations de paires de particules, j'ai trouvé la solution suivante plus rapide que la fonction pdist dans certains cas. 

import numpy as np

L   = 100       # simulation box dimension
N   = 100       # Number of particles
dim = 2         # Dimensions

# Generate random positions of particles
r = (np.random.random(size=(N,dim))-0.5)*L

# uti is a list of two (1-D) numpy arrays  
# containing the indices of the upper triangular matrix
uti = np.triu_indices(100,k=1)        # k=1 eliminates diagonal indices

# uti[0] is i, and uti[1] is j from the previous example 
dr = r[uti[0]] - r[uti[1]]            # computes differences between particle positions
D = np.sqrt(np.sum(dr*dr, axis=1))    # computes distances; D is a 4950 x 1 np array

Voir this pour un regard plus en profondeur sur ce sujet, sur mon blog.

0
shrokmel