На самом деле это отличный пример случая, когда правила широковещательной передачи numpy имеют явные преимущества перед pandas.
Ручное выравнивание координат df1 как векторов столбцов (путем ссылки на df1[[col]].to_numpy()
) и df2. координаты в виде векторов строк (df2[col].to_numpy()
), мы можем очень быстро получить расстояние от каждого элемента в каждом фрейме данных до каждого элемента в другом с помощью автоматической c широковещательной передачи:
In [26]: dists = np.sqrt(
...: (df1[['X']].to_numpy() - df2['X'].to_numpy()) ** 2
...: + (df1[['Y']].to_numpy() - df2['Y'].to_numpy()) ** 2
...: + (df1[['Z']].to_numpy() - df2['Z'].to_numpy()) ** 2
...: )
In [27]: dists
Out[27]:
array([[40.11234224, 7.07106781, 24.35159132, 42.61455151, 46.50806382],
[48.05205511, 10. , 22.29349681, 41.49698784, 49.12229636],
[43.23193264, 5.83095189, 17.74823935, 37.06750599, 42.29657197],
[37.58989226, 11.74734012, 16.52271164, 31.04834939, 33.74907406],
[42.40283009, 16.15549442, 12.56980509, 25.67099531, 30.85449724],
[51.50728104, 13.92838828, 16.58312395, 33.7934905 , 45.04442252],
[47.18050445, 20.32240143, 19.07878403, 22.56102835, 38.85871846],
[38.53569774, 19.33907961, 20.85665361, 25.01999201, 33.7194306 ],
[47.68647607, 18.89444363, 7.07106781, 35.48239 , 28.0713377 ],
[38.60051813, 15.06651917, 16.43167673, 41.96427052, 29.83286778]])
Argmin теперь даст вам правильный вектор позиционных индексов:
In [28]: dists.argmin(axis=0)
Out[28]: array([3, 2, 8, 6, 8])
Или, чтобы выбрать соответствующие значения из df1:
In [29]: df1.iloc[dists.argmin(axis=0)]
Out[29]:
X Y Z
3 7 15 16
2 5 8 9
8 24 14 11
6 2 23 8
8 24 14 11
Edit
Ответ появился сразу после моего, затем был удален, что ссылается на scipy.spatial.distance_matrix
, вычисляя dists
с:
distance_matrix(df1[list('XYZ')].to_numpy(), df2[list('XYZ')].to_numpy())
Не уверен, почему этот ответ был удален, но это кажется действительно хорошим, чистым подход к получению массива, который я создал вручную выше!
Примечание по производительности
Обратите внимание, что если вы просто пытаетесь получить ближайшее значение, нет необходимости брать квадрат root, поскольку это дорогостоящая операция по сравнению с сложением, вычитанием и степенями, и сортировка по dist**2
все еще действительна.