在其他行的31天内有效查找行

时间:2019-04-21 15:24:36

标签: pandas pandas-groupby

我有一个非常大的数据框(> 5GB),其中包含以下信息的行:

PatientID StudyDate Modality SliceNo Filename

每行包含3D医学图像中的一个切片,对于模态,我有PETCT,它们是两种不同类型的医学扫描。例如,我可以拥有:

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扫描之前不到一个月,则定义对应关系。其他扫描可以取消(删除)。通常,可能会有多个CT扫描和多个PT扫描,但是每个CT都应关联一个扫描。例如,如果CT扫描日期为2017-04-01,则在2017-03-01和2017-04-01之间的所有PT扫描都符合条件。

选择满足条件的PT扫描的有效方法是什么:对于该患者,最晚一个月再进行一次CT扫描?

以该示例为例,患者000000001的2016年8月1日的CT将没有相关的PT扫描(可以),但是由于CT的原因,将选择2017年4月1日的PT扫描PT扫描后最多31天进行了2017-04-15扫描。因此,在这种情况下,2017-08-01的PT扫描被过滤掉了。应过滤所有处于这种情况的切片(SliceNo)(每次扫描可以有不同数量的切片)。对于患者000000002,仅保留2015-07-21的PT扫描。

1 个答案:

答案 0 :(得分:1)

以下算法不能涵盖所有情况,但我希望它能对您有所帮助。

首先,我们忽略了一些列,因为实际上我们只对cols = ['PatientID', 'StudyDate', 'Modality']感兴趣。所以我们写

df = df[cols].sort_values(cols).drop_duplicates()

现在,我们确定CTPT期间:

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'])

最后,我们提取PTCT数据。由于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