根据其他列中的值限制多个数据框列

Capping multiple dataframe columns based on values in other columns

这是我在 Whosebug 中的第一个 post,希望我不会违反任何 posting 约定。

我有一个包含 Acct_ID、Current_Balance、Credit_Limit 和每月 EAD 的数据框。 Example Table

import pandas as pd
df = pd.DataFrame({'Acct_ID': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 
                   'Current_Balance': [8000, 7000, 6000, 8000, 7000, 6000, 3000, 2000, 5000, 5000],
                   'Credit_Limit': [10000, 9000, 8000, 7000, 6000, 5000, 4000, 3000, 2000, 1000],
                   'EAD_1': [8500, 7500, 6500, 8500, 7500, 6500, 5500, 4500, 3500, 500],
                   'EAD_2': [9500, 8500, 7500, 6500, 5500, 4500, 3500, 2500, 1500, 1500],
                   'EAD_3': [10500, 9500, 8500, 7500, 6500, 5500, 4500, 3500, 2500, 2000],
                   'EAD_4': [12000, 11000, 10000, 9000, 8000, 7000, 6000, 5000, 4000, 3000]})

我需要对使用以下逻辑的 EAD 列应用上限:

如果当前余额超过信用额度,则每次观察的每月 EAD 为 EAD 和当前余额中的较小者。或者,如果当前余额不超过信用额度,则每次观察的每月 EAD 是 EAD 和信用额度中的较小者。月度 EAD 也应用了 0 下限。

我的背景是 SAS,我最近才开始使用 Python,因此很难找到有效的解决方案。我在下面包含了概述逻辑的 SAS 等价物,仅供参考:

if Current_Balance > Credit_limit then do;
    EAD_&j. = Max(Min(EAD_&j.,Current_Balance),0);
end;

else do;
    EAD_&j. = Max(Min(EAD_&j.,Credit_limit),0); 
end;

我已经在 Python 中找到了可行的解决方案,但这需要很长时间才能达到 运行。我目前正在处理的样本有 325k 个观察值,我需要将“封顶”应用于每月 EAD 的 120 列。目前 Python 中的以下代码需要 40 分钟才能 运行。我不敢 运行 对整个 1200 万条记录进行此操作...作为比较,使用上述脚本在 SAS 中执行相同操作需要 2-3 分钟。

def EAD_LT_adjustment(curr_bal, credit_limit, EAD_t):
    if curr_bal > credit_limit:
        return max(min(EAD_t, curr_bal), 0)
    else:
        return max(min(EAD_t, credit_limit), 0)

for k in range(13, lifetime + 1):
    EL_Acc2['EAD_LT_T' + str(k)] = EL_Acc2.apply(lambda x: EAD_LT_adjustment(x['curr_bal'], x['credit_limit'], x['EAD_LT_T' + str(k)]), axis=1)

有什么优化代码的想法吗? objective 是为了获得相同的结果,但时间明显减少。

谢谢。

DataFrames 非常适合按列操作,这正是您的规则所需要的。例如,这就是我们将您的规则应用到 EAD_1 以得出新列 EAD_1_c

的方式
df.loc[df['Current_Balance'] > df['Credit_Limit'],'EAD_1_c'] = df[['EAD_1','Current_Balance']].min(axis=1).clip(0)
df.loc[df['Current_Balance'] <= df['Credit_Limit'],'EAD_1_c'] = df[['EAD_1','Credit_Limit']].min(axis=1).clip(0)

输出:

      Acct_ID    Current_Balance    Credit_Limit    EAD_1    EAD_2    EAD_3    EAD_4    EAD_1_c
--  ---------  -----------------  --------------  -------  -------  -------  -------  ---------
 0          1               8000           10000     8500     9500    10500    12000       8500
 1          2               7000            9000     7500     8500     9500    11000       7500
 2          3               6000            8000     6500     7500     8500    10000       6500
 3          4               8000            7000     8500     6500     7500     9000       8000
 4          5               7000            6000     7500     5500     6500     8000       7000
 5          6               6000            5000     6500     4500     5500     7000       6000
 6          7               3000            4000     5500     3500     4500     6000       4000
 7          8               2000            3000     4500     2500     3500     5000       3000
 8          9               5000            2000     3500     1500     2500     4000       3500
 9         10               5000            1000      500     1500     2000     3000        500

您可以像在您自己的解决方案中那样遍历所有 EAD_n。我希望这比逐行循环快很多

有关详细信息,请参阅 here and here