更新数据框子集的子集值对于大数据集太慢。

3

问题陈述: 我正在处理一个医院所有就诊事务记录的数据,我需要删除每个患者的第一次以外的坏账交易。

遇到的问题: 我的代码可以在小型数据集上运行,但实际数据集大小约为5GB和1300万行。代码已经运行了数天,仍未完成。背景是,我的代码在一个标准工作计算机上运行,位于Jupyter笔记本中。

示例数据

import pandas as pd

    df = pd.DataFrame({"PatientAccountNumber":[113,113,113,113,225,225,225,225,225,225,225], 
                       "TransactionCode":['50','50','77','60','22','77','25','77','25','77','77'],
                       "Bucket":['Charity','Charity','Bad Debt','3rd Party','Self Pay','Bad Debt',
                                 'Charity','Bad Debt','Charity','Bad Debt','Bad Debt']})
    
    
    print(df)

样例数据框

    PatientAccountNumber TransactionCode     Bucket
0                    113              50    Charity
1                    113              50    Charity
2                    113              77   Bad Debt
3                    113              60  3rd Party
4                    225              22   Self Pay
5                    225              77   Bad Debt
6                    225              25    Charity
7                    225              77   Bad Debt
8                    225              25    Charity
9                    225              77   Bad Debt
10                   225              77   Bad Debt

解决方案

for account in df['PatientAccountNumber'].unique():
    mask = (df['PatientAccountNumber'] == account) & (df['Bucket'] == 'Bad Debt')
    df.drop(df[mask].index[1:],inplace=True)

print(df)

期望结果(每个患者应最多只有一笔坏账交易)

   PatientAccountNumber TransactionCode     Bucket
0                   113              50    Charity
1                   113              50    Charity
2                   113              77   Bad Debt
3                   113              60  3rd Party
4                   225              22   Self Pay
5                   225              77   Bad Debt
6                   225              25    Charity
8                   225              25    Charity

备选方案

for account in df['PatientAccountNumber'].unique():
    mask = (df['PatientAccountNumber'] == account) & (df['Bucket'] == 'Bad Debt')
    mask = mask & (mask.cumsum() > 1)
    df.loc[mask, 'Bucket'] = 'DELETE'

df = df[df['Bucket'] != 'DELETE]

尝试使用Dask

我原以为Dask可以帮助我解决问题,但我却得到了以下错误代码:

  1. 在第一个解决方案中使用Dask - "NotImplementedError:仅支持对具有匹配分区结构的其他系列对象进行系列getitem"
  2. 在第二个解决方案中使用Dask - "TypeError:'_LocIndexer'对象不支持项目分配"
2个回答

3
你可以使用df.duplicated对accountNumber和Bucket进行检查,然后检查Bucket是否为坏账。
df[~(df.duplicated(['PatientAccountNumber','Bucket']) & df['Bucket'].eq("Bad Debt"))]

   PatientAccountNumber TransactionCode     Bucket
0                   113              50    Charity
1                   113              50    Charity
2                   113              77   Bad Debt
3                   113              60  3rd Party
4                   225              22   Self Pay
5                   225              77   Bad Debt
6                   225              25    Charity
8                   225              25    Charity

1
为什么我之前没想到呢!+1 - Corralien
1
太棒了,谢谢!它将处理时间从大约6天缩短到9秒 :) - ResNonVerba

2

创建一个不需要循环的布尔掩码:

mask = df[df['Bucket'].eq('Bad Debt')].duplicated('PatientAccountNumber')
df.drop(mask[mask].index, inplace=True)

>>> df
   PatientAccountNumber TransactionCode     Bucket
0                   113              50    Charity
1                   113              50    Charity
2                   113              77   Bad Debt
3                   113              60  3rd Party
4                   225              22   Self Pay
5                   225              77   Bad Debt
6                   225              25    Charity
8                   225              25    Charity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接