Вот возможное решение, я думаю, что есть способ сделать его более эффективным:
Предполагается, что у вас есть фрейм данных с именем offense_df и фрейм данных с именем defense_df:
В объединенном фрейме данных вы получите ответ на свой вопрос, в основном он создаст следующий фрейм данных:
from scipy.spatial import distance
merged_dataframe = pd.merge(offense_df,defense_df,on=['GameTime','PlayId'],suffixes=('_off','_def'))
GameTime PlayId PlayerId_off x-coord_off y-coord_off PlayerId_def x-coord_def y-coord_def
0 1 1 751 30.2 15.0 117 20.2 20.0
1 1 1 751 30.2 15.0 555 40.1 17.0
2 1 1 419 41.3 15.0 117 20.2 20.0
3 1 1 419 41.3 15.0 555 40.1 17.0
4 1 1 989 10.1 15.0 117 20.2 20.0
Следующие две строки здесь, чтобы создать уникальный столбец для координат, в основном он создаст для нарушителя (ordin_off) и для защитника столбец (Coord_def), который содержит кортеж (X, Y), это упростит вычисление расстояния.
merged_dataframe['coord_off'] = merged_dataframe.apply(lambda x: (x['x-coord_off'], x['y-coord_off']),axis=1)
merged_dataframe['coord_def'] = merged_dataframe.apply(lambda x: (x['x-coord_def'], x['y-coord_def']),axis=1)
Мы вычисляем расстояние до всех защитников в данный GameTime, PlayId.
merged_dataframe['distance_to_def'] = merged_dataframe.apply(lambda x: distance.euclidean(x['coord_off'],x['coord_def']),axis=1)
Для каждого PlayerId, GameTime, PlayId мы берем расстояние до ближайшего защитника.
smallest_dist = merged_dataframe.groupby(['GameTime','PlayId','PlayerId_off'])['distance_to_def'].min()
Наконец, мы берем максимальное расстояние (из этих минимальных расстояний) для каждого PlayerId.
smallest_dist.groupby('PlayerId_off').max()