曾经违约标记 - 用于信用风险建模 - Python

Ever Default Tagging - for Credit Risk Modelling- Python

我是 python 的新手,在编写这部分代码时遇到了一些困难。因此,为了提供背景知识,我想为信用风险建模做一个永远默认的标记。

0 用于非默认帐户和 默认帐户 1 个

所以 idea/concept 是整个日期性能(12 个月),如果特定客户 (ID) 曾经有过一次违约事件 (1),那么该事件之后的下一次性能(对于那个customer) 将被标记为默认值 (1),即使 'default tagging' 为 0.

所以输入是这样的:

ID Date Performance Default Tag
AAA 2021-03-01 0
AAA 2021-04-01 0
AAA 2021-05-01 0
AAA 2021-06-01 0
AAA 2021-07-01 0
AAA 2021-08-01 0
AAA 2021-09-01 0
AAA 2021-10-01 0
AAA 2021-11-01 0
AAA 2021-12-01 0
AAA 2022-01-01 0
AAA 2022-02-01 0
ABB 2021-03-01 0
ABB 2021-04-01 0
ABB 2021-05-01 0
ABB 2021-06-01 1
ABB 2021-07-01 0
ABB 2021-08-01 0
ABB 2021-09-01 1
ABB 2021-10-01 0
ABB 2021-11-01 0
ABB 2021-12-01 0
ABB 2022-01-01 0
ABB 2022-02-01 0

并且输出将出现在这样的新列中:

ID Date Performance Ever Default Tag
AAA 2021-03-01 0
AAA 2021-04-01 0
AAA 2021-05-01 0
AAA 2021-06-01 0
AAA 2021-07-01 0
AAA 2021-08-01 0
AAA 2021-09-01 0
AAA 2021-10-01 0
AAA 2021-11-01 0
AAA 2021-12-01 0
AAA 2022-01-01 0
AAA 2022-02-01 0
ABB 2021-03-01 0
ABB 2021-04-01 0
ABB 2021-05-01 0
ABB 2021-06-01 1
ABB 2021-07-01 1
ABB 2021-08-01 1
ABB 2021-09-01 1
ABB 2021-10-01 1
ABB 2021-11-01 1
ABB 2021-12-01 1
ABB 2022-01-01 1
ABB 2022-02-01 1

请试试这个:

df = df.reset_index(drop=True)
for id in df['ID'].unique():
  try:
    df.loc[df['ID']==id,['Ever Default Tag']] = 0
    index_value = list(df[(df['ID']==id)&(df['Default Tag']==1)].index)[0]
    df.loc[index_value:,['Ever Default Tag']] = 1
  except:
    continue
df['Ever Default Tag'] = df['Ever Default Tag'].astype(int)

这里有一些代码可以完成您的问题:

(UPDATED 将 one-line lambda 替换为 apply 更具可读性的函数,并更正默认时的 off-by-one 错误开始。)

import pandas as pd
records = [
    {'ID':'AAA', 'Date Performance': '2021-03-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-04-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-05-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-06-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-07-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-08-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-09-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-10-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-11-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2021-12-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2022-01-01', 'Default Tag': 0},
    {'ID':'AAA', 'Date Performance': '2022-02-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-03-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-04-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-05-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-06-01', 'Default Tag': 1},
    {'ID':'AAB', 'Date Performance': '2021-07-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-08-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-09-01', 'Default Tag': 1},
    {'ID':'AAB', 'Date Performance': '2021-10-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-11-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2021-12-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2022-01-01', 'Default Tag': 0},
    {'ID':'AAB', 'Date Performance': '2022-02-01', 'Default Tag': 0}
]
df = pd.DataFrame(records)
def hasEverDefaulted(df, x):
    id, dt = 'ID', 'Date Performance'
    hasSameIdAndNotLaterDate = (df[id] == x[id]) & (df[dt] <= x[dt])
    return int(sum(df[hasSameIdAndNotLaterDate]['Default Tag']) > 0)
df['Default Tag'] = df.apply(lambda x: hasEverDefaulted(df, x), axis=1)
df.rename(columns={'Default Tag': 'Ever Default Tag'}, inplace=True)
print(df)

输出:

     ID Date Performance  Ever Default Tag
0   AAA       2021-03-01                 0
1   AAA       2021-04-01                 0
2   AAA       2021-05-01                 0
3   AAA       2021-06-01                 0
4   AAA       2021-07-01                 0
5   AAA       2021-08-01                 0
6   AAA       2021-09-01                 0
7   AAA       2021-10-01                 0
8   AAA       2021-11-01                 0
9   AAA       2021-12-01                 0
10  AAA       2022-01-01                 0
11  AAA       2022-02-01                 0
12  AAB       2021-03-01                 0
13  AAB       2021-04-01                 0
14  AAB       2021-05-01                 0
15  AAB       2021-06-01                 1
16  AAB       2021-07-01                 1
17  AAB       2021-08-01                 1
18  AAB       2021-09-01                 1
19  AAB       2021-10-01                 1
20  AAB       2021-11-01                 1
21  AAB       2021-12-01                 1
22  AAB       2022-01-01                 1
23  AAB       2022-02-01                 1

更新#2: 以下是对 apply().

的调用所发生情况的解释

当您使用参数 axis=1 调用 pandas 中类型 DataFrame 的对象的 apply() 方法时,它会为每一行重复调用指定的函数DataFrame 对象和 Series 对象,该对象包含给定行的 DataFrame 对象的列中的值。

在此答案的代码中,被调用的函数是一个 lambda,以给定的行作为参数 x,它又以参数 [=23] 调用 hasEverDefaulted() =] 和 x.

hasEverDefaulted() 中,我们进行矢量化逻辑计算以获得一列 boolean 值,该列扫描 df 的整个 'ID' 列,检查是否与'ID'x 中的值,并扫描整个 'Date Performance' 列检查 <=x 中的日期值的日期值。然后,我们使用矢量化逻辑“与”运算符 & 将这些和 select(通过将对应于 x 的结果行设置为 True)仅与当前匹配的值组合行的“id”并且还有一个不晚于当前行的“日期”。我们将此矢量化(柱状)结果分配给变量 hasSameIdAndNotLaterDate.

然后,我们将此变量用作 boolean 过滤器,从 dfTrue 行到 select,然后我们对 Default Tag 求和这些行的列值,通过测试此总和来创建一个 boolean 值,以检查它是否为 > 0(在这种情况下,该行的 'ID' 在该行的 [=31 上或之前出现默认值=]) 和 return 此 boolean 值的 int 版本(即 01)。

在调用 apply() 的语句中,我们将 apply() 的列式结果分配给 df'Default Tag' 列。为了清楚地表明我们现在已经更改了此列的语义(现在指示默认是否发生在每行的 'Date Performance' 日期或之前),我们调用 [=15] 的 rename() 方法=] object df 将列名称更改为 'Ever Default Tag'.