Hi here is a possible solution using only Pandas
Let's give the current index a name (for convenience and be sure that we recover everything well)
df['Date'] = df['Date'].astype('datetime64[ns]')
df.index.name = 'id'
We are first going to sort by date and apply a function to each group,
it is important to note that we are going to rely on the fact that pandas preserve the row order inside a group (see documentation)
sorted_df = sorted_df = df.sort_values('Date')
result_df = sorted_df.groupby('A_key').apply(nearest_date_distance)
So now let see what we have inside the nearest_date_distance function
The function relies on the fact that the Date will be sorted , therefore we compute the time to the date before and the time to the date after, the difference between the current day and the next day is negative that's why we add the .abs().Finally we take the minimum between these two distances (btw the min operator won't take the missing value (NaT) that you have for the first row of time_to_before and last row of time to after)
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
Finally I lied a bit result_df will be a MultiIndex Serie (not a dataframe) of this form:
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
We can easily convert it to a DataFrame and having a proper naming for our original index helps to see that everything is indexed the same as in the original 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
and if you need the Date on the resulting Dataframe result_df['Date'] = df['Date']should do the trick :)