web-dev-qa-db-fra.com

Formule de distance entre deux points d'une liste

Je dois prendre une liste que j'ai créée et trouver les deux points les plus proches et les imprimer. Comment puis-je comparer chaque point de la liste?

Il n'est pas nécessaire de tracer ou quoi que ce soit, il suffit de comparer les points et de trouver les deux plus proches dans la liste.

import math # 'math' needed for 'sqrt'

# Distance function
def distance(xi,xii,yi,yii):
    sq1 = (xi-xii)*(xi-xii)
    sq2 = (yi-yii)*(yi-yii)
    return math.sqrt(sq1 + sq2)

# Run through input and reorder in [(x, y), (x,y) ...] format
oInput = ["9.5 7.5", "10.2 19.1", "9.7 10.2"] # Original input list (entered by spacing the two points).
mInput = [] # Manipulated list
fList = [] # Final list
for o in oInput:
    mInput = o.split()
    x,y = float(mInput[0]), float(mInput[1])
    fList += [(x, y)] # outputs [(9.5, 7.5), (10.2, 19.1), (9.7, 10.2)]
20
morcutt

Il est plus pratique de réécrire votre fonction distance() pour prendre deux tuples (x, y) en tant que paramètres:

def distance(p0, p1):
    return math.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)

Vous souhaitez maintenant parcourir toutes les paires de points de votre liste fList. La fonction iterools.combinations() est pratique pour cela:

min_distance = distance(fList[0], fList[1])
for p0, p1 in itertools.combinations(fList, 2):
    min_distance = min(min_distance, distance(p0, p1))

Une alternative consiste à définir distance() pour accepter la paire de points dans un seul paramètre.

def distance(points):
    p0, p1 = points
    return math.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)

et utilisez le paramètre key pour la fonction min() intégrée:

min_pair = min(itertools.combinations(fList, 2), key=distance)
min_distance = distance(min_pair)
34
Sven Marnach

Je me rends compte qu'il y a des contraintes de librairie sur cette question, mais pour être complet, si vous avez N points dans un Np2 numpy ndarray (système 2D):

from scipy.spatial.distance import pdist
x = numpy.array([[9.5,7.5],[10.2,19.1],[9.7,10.2]])
mindist = numpy.min(pdist(x))

J'essaie toujours d'encourager les gens à utiliser numpy/scipy s'ils traitent des données qui sont mieux stockées dans un tableau numérique et qu'il est bon de savoir que les outils sont disponibles pour référence future.

11
JoshAdel

Notez que la fonction math.sqrt est à la fois lente et, dans ce cas, inutile. Essayez de comparer la distance au carré pour l'accélérer (les distances de tri par rapport à la distance au carré produiront toujours le même ordre):

def distSquared(p0, p1):
    return (p0[0] - p1[0])**2 + (p0[1] - p1[1])**2
2
Aaron Dufour

Votre code fixe. Aucun algorithme efficace, juste celui de la force brute.

import math # math needed for sqrt

# distance function
def dist(p1, p2):
    return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2)

# run through input and reorder in [(x, y), (x,y) ...] format
input = ["9.5 7.5", "10.2 19.1", "9.7 10.2"] # original input list (entered by spacing the two points)
points = [map(float, point.split()) for point in input] # final list

# http://en.wikipedia.org/wiki/Closest_pair_of_points
mindist = float("inf")
for p1, p2 in itertools.combinations(points, 2):
    if dist(p1, p2) < mindist:
        mindist = dist(p1, p2)
        closestpair = (p1, p2)

print(closestpair)
2
orlp

Cela pourrait fonctionner:

oInput = ["9.5 7.5", "10.2 19.1", "9.7 10.2"]

# parse inputs
inp = [(float(j[0]), float(j[1])) for j in [i.split() for i in oInput]]

# initialize results with a really large value
min_distance = float('infinity')
min_pair = None

# loop over inputs
length = len(inp)
for i in xrange(length):
    for j in xrange(i+1, length):
        point1 = inp[i]
        point2 = inp[j]

        if math.hypot(point1[0] - point2[0], point1[1] - point2[0]) < min_distance:
            min_pair = [point1, point2]

une fois les boucles terminées, min_pair devrait être la paire avec la plus petite distance.

L'utilisation de float () pour analyser le texte laisse place à des améliorations.

math.hypot est environ un tiers plus rapide que le calcul de la distance dans une fonction manuscrite en python

1
HumanCatfood

Tout d'abord, quelques notes:

a**2 # squares a
(xi - xii)**2 # squares the expression in parentheses.

mInput n'a pas besoin d'être déclaré à l'avance.
fList.append((x, y)) est plus Pythonique que d'utiliser +=.

Maintenant vous avez fList. Votre fonction distance peut être réécrite pour prendre 2 arguments de 2 tuple (point), que je ne vais pas aborder ici.

Ensuite, vous pouvez simplement écrire:

shortest = float('inf')
for pair in itertools.combinations(fList, 2):
    shortest = min(shortest, distance(*pair))
0
nmichaels