Привет, вот возможное решение с использованием только панд
Давайте дадим имя текущему индексу (для удобства и будем уверены, что мы все хорошо восстановим)
df['Date'] = df['Date'].astype('datetime64[ns]')
df.index.name = 'id'
Сначала мы отсортируем по дате и применим функцию к каждой группе,
важно отметить, что мы будем полагаться на тот факт, что панды сохраняют порядок строк внутри группы (см. документацию)
sorted_df = sorted_df = df.sort_values('Date')
result_df = sorted_df.groupby('A_key').apply(nearest_date_distance)
Итак, давайте посмотрим, что у нас есть внутри функции nearest_date_distance
Функция основана на том факте, что Дата будет отсортирована, поэтому мы вычисляем время до даты до и после даты, разница между текущим днем и следующим днем отрицательная, поэтому мы добавляем .abs()
. Наконец, мы берем минимум между этими двумя расстояниями (кстати, оператор min не примет пропущенное значение (NaT), которое у вас есть для первой строки time_to_before и последней строки времени после)
def nearest_date_distance(sub):
time_to_before = sub['Date'].diff()
time_to_after = sub['Date'].diff(-1).abs()
nearest_date_distance = pd.concat([time_to_before, time_to_after],axis=1).min(axis=1)
nearest_date_distance.name = 'Distance'
return nearest_date_distance
Наконец, я немного соврал result_df
будет MultiIndex Serie (не датафрейм) этой формы:
A_key id
A1 0 145 days
1 145 days
A2 2 0 days
3 0 days
A3 4 163 days
5 26 days
6 26 days
A4 7 0 days
8 0 days
Мы можем легко преобразовать его в DataFrame, и правильное именование нашего исходного индекса помогает увидеть, что все проиндексировано так же, как и в оригинальном df.
result_df =sorted_df.groupby('A_key').apply(nearest_date_distance).reset_index(level=0)
A_key Distance
id
0 A1 145 days
1 A1 145 days
2 A2 0 days
3 A2 0 days
4 A3 163 days
5 A3 26 days
6 A3 26 days
7 A4 0 days
8 A4 0 days
и если вам нужна дата в итоговом кадре данных result_df['Date'] = df['Date']
, то добьетесь цели:)