tengo un punto
point = np.array([0.07852388, 0.60007135, 0.92925712, 0.62700219, 0.16943809, 0.34235233])Y un marco de datos de pandas
abcdef 0 0.025641 0.554686 0.988809 0.176905 0.050028 0.333333 1 0.027151 0.520914 0.985590 0.409572 0.163980 0.424242 2 0.028788 0.478810 0.970480 0.288557 0.095053 0.939394 3 0.018692 0.450573 0.985910 0.178048 0.118399 0.484848 4 0.023256 0.787253 0.865287 0.217591 0.205670 0.303030Me gustaría calcular la distancia de cada fila en el marco de datos de pandas, a ese punto específico
Lo intenté
import numpy as np d_all = list() for index, row in df_scaled[cols_list].iterrows(): d = np.linalg.norm(centroid-np.array(list(row[cols_list]))) d_all += [d] df_scaled['distance_cluster'] = d_allSin embargo, mi solución es realmente lenta (teniendo en cuenta que también quiero calcular la distancia desde otros puntos).
¿Hay alguna manera de hacer mis cálculos de manera más eficiente?
Puede calcular la distancia euclidiana vectorizada (norma L2) usando la fórmula
sqrt((a 1 - b 1 ) 2 + (a 2 - b 2 ) 2 + ...)
df.sub(point, axis=1).pow(2).sum(axis=1).pow(.5) 0 0.474690 1 0.257080 2 0.703857 3 0.503596 4 0.461151 dtype: float64Lo que da el mismo resultado que su código actual.
O, usando linalg.norm :
np.linalg.norm(df.to_numpy() - point, axis=1) # array([0.47468985, 0.25707985, 0.70385676, 0.5035961 , 0.46115096])Otra opción es usar cdist que es un poco más rápido:
from scipy.spatial.distance import cdist cdist(point[None,], df.values)Producción:
array([[0.47468985, 0.25707985, 0.70385676, 0.5035961 , 0.46115096]])Alguna comparación con 100k filas:
%%timeit -n 10 cdist([point], df.values) 645 µs ± 36.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) %%timeit -n 10 np.linalg.norm(df.to_numpy() - point, axis=1) 5.16 ms ± 227 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) %%timeit -n 10 df.sub(point, axis=1).pow(2).sum(axis=1).pow(.5) 16.8 ms ± 444 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)Hagamos scipy
from scipy.spatial import distance ary = distance.cdist(df.values, np.array([point]), metric='euclidean') ary Out[57]: array([[0.47468985], [0.25707985], [0.70385676], [0.5035961 ], [0.46115096]])Un poco tarde, pero puede apply la función np.ligalg.norm al marco de datos.
df['distance_cluster'] = df.apply(lambda x : np.linalg.norm(x-point),1)Salida :
#print(df['distance_cluster']) 0 0.474690 1 0.257080 2 0.703857 3 0.503596 4 0.461151 dtype: float64 Sin embargo, sería considerablemente más lento en comparación con las soluciones numpy .