web-dev-qa-db-fra.com

Le moyen le plus rapide de calculer le centroïde d'un jeu de tuples de coordonnées en python sans Numpy

J'ai travaillé sur un projet extrêmement sensible au temps (qui doit malheureusement être en python) et l'une des fonctions largement utilisées est une fonction qui calcule le centroïde d'une liste de (x, y) tuples. Pour illustrer:

def centroid(*points):
    x_coords = [p[0] for p in points]
    y_coords = [p[1] for p in points]
    _len = len(points)
    centroid_x = sum(x_coords)/_len
    centroid_y = sum(y_coords)/_len
    return [centroid_x, centroid_y]

>>> centroid((0, 0), (10, 0), (10, 10), (0, 10))
[5, 5]

Cette fonction est assez rapide. L’exemple ci-dessus s’achève en moyenne en 1,49e-05 secondes sur mon système, mais je cherche le moyen le plus rapide de calculer le centroïde. Avez-vous des idées?

Une de mes solutions consistait à effectuer les opérations suivantes (où l est la liste des n-uplets):

map(len(l).__rtruediv__, map(sum, Zip(*l)))

Ce qui se situe entre 1.01e-05 et 9.6e-06 secondes, mais se convertit malheureusement en une liste (en entourant toute la déclaration dans list( ... )) presque double temps de calcul.

EDIT: Les suggestions sont les bienvenues en python pur MAIS PAS numpy.

EDIT2: Je viens de découvrir que si une variable distincte est conservée pour la longueur de la liste de tuples, l’implémentation ci-dessus avec map fonctionne de manière fiable sous 9.2e-06 secondes, mais le problème de la conversion en liste est toujours présent.

EDIT3:

Maintenant, je n'accepte que des réponses en python pur, PAS en numpy (désolé pour ceux qui ont déjà répondu en numpy!)

20
user3002473
import numpy as np

data = np.random.randint(0, 10, size=(100000, 2))

c'est rapide

def centeroidnp(arr):
    length = arr.shape[0]
    sum_x = np.sum(arr[:, 0])
    sum_y = np.sum(arr[:, 1])
    return sum_x/length, sum_y/length

%timeit centeroidnp(data)
10000 loops, best of 3: 181 µs per loop

étonnamment, c'est beaucoup plus lent:

%timeit data.mean(axis=0)
1000 loops, best of 3: 1.75 ms per loop

numpy me semble très rapide ...

Pour être complet:

def centeroidpython(data):
    x, y = Zip(*data)
    l = len(x)
    return sum(x) / l, sum(y) / l
#take the data conversion out to be fair!
data = list(Tuple(i) for i in data)

%timeit centeroidpython(data)
10 loops, best of 3: 57 ms per loop
15
Retozi

Ceci est une implémentation naïve de Numpy, je ne peux pas le chronométrer ici alors je me demande comment cela fonctionne:

import numpy as np

arr = np.asarray(points)
length = arr.shape[0]
sum_x = np.sum(arr[:, 0])
sum_y = np.sum(arr[:, 1])
return sum_x / length, sum_y / length

Vous transmettez les points à centroid() sous forme de paramètres distincts, qui sont ensuite placés dans un seul Tuple avec *points. Il serait plus rapide de simplement passer une liste ou un itérateur avec des points.

0
RemcoGerlich