La mejor manera de pasar un parámetro repetido a una función vectorizada Numpy

Entonces, continuando de la discusión que tuvimos en esta respuesta @TheBlackCat y yo, me gustaría saber la mejor manera de pasar argumentos a una función vectorizada Numpy. La función en cuestión se define así:

vect_dist_funct = np.vectorize(lambda p1, p2: vincenty(p1, p2).meters) 

donde, vincenty viene del paquete Geopy .

Actualmente llamo a vect_dist_funct de esta manera:

 def pointer(point, centroid, tree_idx): intersect = list(tree_idx.intersection(point)) if len(intersect) > 0: points = pd.Series([point]*len(intersect)).values polygons = centroid.loc[intersect].values dist = vect_dist_funct(points, polygons) return pd.Series(dist, index=intercept, name='Dist').sort_values() else: return pd.Series(np.nan, index=[0], name='Dist') points['geometry'].apply(lambda x: pointer(point=x.coords[0], centroid=line['centroid'], tree_idx=tree_idx)) 

(Por favor, consulte la pregunta aquí: tipos de datos etiquetados Python )

Mi pregunta se refiere a lo que sucede dentro del pointer función. La razón por la que estoy convirtiendo los points en una serie de pandas.Series luego obteniendo los valores (en la cuarta línea, justo debajo de la instrucción if ) es para que tenga la misma forma que los polígonos. Si simplemente invoco puntos como points = [point]*len(intersect) o como points = itertools.repeat(point, len(intersect)) , Numpy se queja de que “no puede transmitir matrices de tamaño (n, 2) y tamaño (n,) juntos “(n es la longitud de la intersect ).

Si llamo vect_dist_funct así: dist = vect_dist_funct(itertools.repeat(points, len(intersect)), polygons) , vincenty queja de que le he pasado demasiados argumentos. Estoy en una pérdida completa para entender la diferencia entre los dos.

Tenga en cuenta que estas son coordenadas, por lo tanto siempre estarán en pares. Aquí hay ejemplos de cómo se ven los point y los polygons :

 point = (-104.950752 39.854744) # Passed directly to the function like this. polygons = array([(-104.21750802451864, 37.84052458697633), (-105.01017084789603, 39.82012158954065), (-105.03965315742742, 40.669867471420886), (-104.90353460825702, 39.837631505433706), (-104.8650601872832, 39.870796282334744)], dtype=object) # As returned by statement centroid.loc[intersect].values 

¿Cuál es la mejor manera de llamar a vect_dist_funct en esta circunstancia, de modo que pueda recibir una llamada vectorizada y Numpy y Vincent no se quejarán de que estoy transmitiendo argumentos erróneos? Además, se buscan técnicas que den como resultado un consumo mínimo de memoria y una mayor velocidad. El objective es calcular la distancia entre el punto a cada centroide polígono.

np.vectorize realmente no te ayuda aquí. Según la documentación :

La función vectorizar se proporciona principalmente por conveniencia, no por desempeño. La implementación es esencialmente un bucle for.

De hecho, vectorize daño a usted, ya que convierte las entradas en matrices numpy, realizando una conversión de tipo innecesaria y costosa y produciendo los errores que está viendo. Está mucho mejor usando una función con un bucle for .

También es mejor usar una función en lugar de un lambda para una función de nivel, ya que le permite tener una cadena de documentos.

Así es como implementaría lo que estás haciendo:

 def vect_dist_funct(p1, p2): """Apply `vincenty` to `p1` and each element of `p2`. Iterate over `p2`, returning `vincenty` with the first argument as `p1` and the second as the current element of `p2`. Returns a numpy array where each row is the result of the `vincenty` function call for the corresponding element of `p2`. """ return [vincenty(p1, p2i).meters for p2i in p2] 

Si realmente desea usar vectorize , puede usar el argumento excluded para no vectorizar el argumento p1 , o mejor aún, configurar un lambda que se vincenty y solo vincenty el segundo argumento:

 def vect_dist_funct(p1, p2): """Apply `vincenty` to `p1` and each element of `p2`. Iterate over `p2`, returning `vincenty` with the first argument as `p1` and the second as the current element of `p2`. Returns a list where each value is the result of the `vincenty` function call for the corresponding element of `p2`. """ vinc_p = lambda x: vincenty(p1, x) return np.vectorize(vinc_p)(p2)