Следующий алгоритм не охватывает все случаи, но я надеюсь, что он тоже поможет.
Сначала мы игнорируем некоторые столбцы, потому что на самом деле нас интересует только cols = ['PatientID', 'StudyDate', 'Modality']
.Итак, мы пишем
df = df[cols].sort_values(cols).drop_duplicates()
Теперь мы определяем периоды CT
и PT
:
df['Modality_'] = df.groupby(['PatientID'])['Modality'].shift(1).fillna(method='bfill')
df['Group'] = (1-df['Modality_'].eq(df['Modality'])).cumsum()
Затем мы вычисляем максимальную и минимальную даты в каждом периоде
agg = df.pivot_table(index=['PatientID', 'Group'], columns=['Modality'], values=['StudyDate'], aggfunc=['max', 'min'])
Наконец, мы извлекаем данные PT
и CT
.Поскольку за периодом PT
всегда следует период CT
, мы можем сместить предыдущую группу на единицу и сравнить их напрямую
pt = agg.loc[:, ('max', 'StudyDate', 'PT')].groupby(['PatientID']).shift(1)
ct = agg.loc[:, ('min', 'StudyDate', 'CT')]
Мы хотим выбрать даты, где смещение составляет менее 30 дней:
ok = ct - pt < pd.offsets.Day(30)
ok = ok[ok == True].to_frame()
Теперь мы закончили:
print(ok.join(ct.to_frame()))
0 (max, StudyDate, CT)
PatientID Group
1 2 True 2017-04-15
2 4 True 2015-08-05
print(ok.join(pt.to_frame()))
0 (max, StudyDate, PT)
PatientID Group
1 2 True 2017-04-01
2 4 True 2015-07-21