#pandas #pandas-groupby
#pandas #pandas-groupby
Вопрос:
У меня очень большой фрейм данных (> 5 ГБ), в котором есть строки со следующей информацией:
PatientID StudyDate Modality SliceNo Filename
Каждая строка состоит из фрагмента 3D-медицинского изображения, а для модальности у меня есть PET
и CT
, которые представляют собой два разных типа медицинских сканирований. Например, я мог бы:
PatientID StudyDate Modality SliceNo Filename
000000001 2017-08-01 PT 0 XXXXX
000000001 2017-08-01 PT 1 XXXXX
...
000000001 2017-08-01 PT 100 XXXXX
000000001 2017-04-01 PT 0 XXXXX
000000001 2017-04-01 PT 1 XXXXX
...
000000001 2016-08-01 CT 0 XXXXX
000000001 2016-08-01 CT 1 XXXXX
...
000000001 2016-08-01 CT 100 XXXXX
000000001 2017-04-15 CT 0 XXXXX
000000001 2017-04-15 CT 1 XXXXX
...
000000001 2017-04-15 CT 100 XXXXX
...
000000002 2016-07-01 PT 0 XXXXX
000000002 2016-07-01 PT 1 XXXXX
...
000000002 2016-07-01 PT 100 XXXXX
000000002 2015-07-21 PT 0 XXXXX
000000002 2015-07-21 PT 1 XXXXX
...
000000002 2015-07-21 PT 100 XXXXX
000000002 2014-07-01 PT 0 XXXXX
000000002 2014-07-01 PT 1 XXXXX
...
000000002 2014-07-01 PT 100 XXXXX
000000002 2015-08-05 CT 0 XXXXX
000000002 2015-08-05 CT 1 XXXXX
...
000000002 2015-08-05 CT 100 XXXXX
Теперь я хотел бы найти для PT
каждого пациента, которые соответствуют CT
сканированию, где определяется соответствие, если оно было сделано менее чем за месяц до CT
сканирования. Другие проверки могут быть отклонены (отброшены). В общем случае может быть проведено несколько КТ-сканирований и несколько ПТ-сканирований, но с каждой КТ должно быть связано одно сканирование. Например, если дата КТ-сканирования будет 2017-04-01, все КТ-сканы между 2017-03-01 и 2017-04-01 будут соответствовать требованиям.
Каков эффективный способ выбора тех томографических снимков, которые удовлетворяют условию: для этого пациента компьютерная томография проводится максимум через месяц?
Для примера и пациента 000000001
КТ 2016-08-01 не будет иметь соответствующего сканирования PT (что нормально), но сканирование PT 2017-04-01 будет выбрано, потому что сканирование CT 2017-04-15 было выполнено максимум через 31 день после сканирования PT. Итак, в этом случае отфильтровывается просмотр PT 2017-08-01. Все фрагменты ( SliceNo
) (может быть разное количество фрагментов на сканирование) с этим условием должны быть отфильтрованы. Для пациента 000000002
сохраняется только сканирование PT 2015-07-21.
Комментарии:
1. Что именно означает «за месяц до»? Если
CT
датой является2016-08-15
, для каких дат это допустимоPT
?2. @JoergVanAken с 2016-07-15 по 2016-08-15 будут действительными очками!
3. Не могли бы вы предоставить еще несколько примеров данных и ожидаемый результат? У меня есть несколько идей, но я не уверен, применимы ли они.
4. @JoergVanAken попытался немного расширить его. Вкратце, все снимки PT пациента, которые не были сделаны максимум за месяц до компьютерной томографии пациента, должны быть отфильтрованы.
5. Привет, Джонас, ты видел мой ответ?
Ответ №1:
Следующий алгоритм не охватывает все случаи, но я надеюсь, что он также поможет.
Сначала мы игнорируем некоторые столбцы, потому что на самом деле нас интересуют только 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