Pandas中的条件累加和

9

我曾是一名Excel高级用户,现在后悔自己的过错。我需要帮助重新创建一个常见的计算。

我正在尝试计算贷款组合的表现。在分子中,我正在计算损失的累计总额。在分母中,我需要包括在累计总额中的贷款的原始余额。

我无法想出如何在Pandas中进行条件分组来完成此操作。这在Excel中非常简单,因此我希望自己没有想太多。

我在StackOverflow上没有找到太多相关问题,但以下链接最为接近:python pandas conditional cumulative sum

我无法确定的是我的条件是基于索引中的值以及包含在列中的值。

以下是我的数据:

| Loan    | Origination | Balance | NCO Date  | NCO | As of Date | Age     (Months) | NCO Age (Months) |
|---------|-------------|---------|-----------|-----|------------|--------------|------------------|
| Loan 1  | 1/31/2011   | 1000    | 1/31/2018 | 25  | 5/31/2019  | 100              | 84               |
| Loan 2  | 3/31/2011   | 2500    |           | 0   | 5/31/2019  | 98           |                  |
| Loan 3  | 5/31/2011   | 3000    | 1/31/2019 | 15  | 5/31/2019  | 96           | 92               |
| Loan 4  | 7/31/2011   | 2500    |           | 0   | 5/31/2019  | 94           |                  |
| Loan 5  | 9/30/2011   | 1500    | 3/31/2019 | 35  | 5/31/2019  | 92           | 90               |
| Loan 6  | 11/30/2011  | 2500    |           | 0   | 5/31/2019  | 90           |                  |
| Loan 7  | 1/31/2012   | 1000    | 5/31/2019 | 5   | 5/31/2019  | 88           | 88               |
| Loan 8  | 3/31/2012   | 2500    |           | 0   | 5/31/2019  | 86           |                  |
| Loan 9  | 5/31/2012   | 1000    |           | 0   | 5/31/2019  | 84           |                  |
| Loan 10 | 7/31/2012   | 1250    |           | 0   | 5/31/2019  | 82           |                  |

在 Excel 中,我将使用以下公式计算总额:
未偿余额行:=SUMIFS(Balance,Age (Months),Reference Age)
Cumulative NCO: =SUMIFS(NCO,Age (Months),>=Reference Age,NCO Age (Months),<=&Reference Age)

数据:

| Reference Age       | 85    | 90    | 95   | 100  
|---------------------|-------|-------|------|------
| Outstanding Balance | 16500 | 13000 | 6500 | 1000 
| Cumulative NCO      | 25    | 60    | 40   | 25   

这里的目标是,在“未清余额(Outstanding Balance)”中包括已经够旧以至于需要一个“非履约观察期(NCO)”来进行观察的项目。而“NCO”是指截止到当期为止尚未还清的贷款总额。

编辑:

我已经得到了一种计算方法,但这是最有效的方法吗?

age_bins = list(np.arange(85, 101, 5))
final_df = pd.DataFrame()
df.fillna(value=0, inplace=True)
df["NCO Age (Months)"] = df["NCO Age (Months)"].astype(int)

for x in age_bins:

    age = x

    nco = df.loc[(df["Age (Months)"] >= x) & (df["NCO Age (Months)"] <= x), "NCO"].sum()

    bal = df.loc[(df["Age (Months)"] >= x), "Balance"].sum()

    temp_df = pd.DataFrame(
        data=[[age, nco, bal]],
        columns=["Age", "Cumulative NCO", "Outstanding Balance"],
        index=[age],
    )

    final_df = final_df.append(temp_df, sort=True)

1
什么是引用年龄? - Scott Boston
抱歉,我标记错误了。参考资料应该是数据部分的月份(年龄)。我会编辑帖子。 - Russ W
Excel的累计总和和Pandas/Python的一样吗?这是我经常遇到困难的地方,相同的函数却有所不同,例如Python的round使用银行家舍入(从0.5向下舍入),而Excel则向上舍入。当我在Python中重新编写VBA代码时,这给我带来了一些问题!你的问题基础很好,但我发现很难从你的例子中理解你的输出。 - Umar.H
3个回答

2

您使用了依赖于变量的复杂条件。对于简单的累积和,很容易找到矢量化的方法,但我无法想象一种优雅的方式来处理Cumulative NCO。

因此,我会回归到Python推导式:

Original Answer翻译成"最初的回答"

data = [
    { 'Reference Age': ref,
      'Outstanding Balance': df.loc[df.iloc[:,6]>=ref,'Balance'].sum(),
      'Cumulative NCO': df.loc[(df.iloc[:,6]>=ref)&(df.iloc[:,7]<=ref),
                   'NCO'].sum() }
    for ref in [85, 90, 95, 100]]

result = pd.DataFrame(data).set_index('Reference Age').T

它产生:

Reference Age          85     90    95    100
Cumulative NCO          25     60    40    25
Outstanding Balance  16500  13000  6500  1000

这看起来平衡还不错,但是NCO是错误的。它获取了第85列所有NCO的总和,尽管在该时间段内只有1个NCO发生。 - Russ W
@RussW,由于我不是Excel公式的专家,并且我的Excel中的公式名称是法语,因此我不理解如何计算累积MCO。这个答案是错误的,除非我找到正确的方法,否则它将被删除。 - Serge Ballesta
@RussW:这个不太优化,但满足你的“SUMIFS”要求。 - Serge Ballesta
谢谢!这看起来正是我所需要的。 - Russ W

0
您可以尝试使用pd.cut构建给定年龄范围内的贷款组,然后使用groupby。像这样:
import pandas as pd

df = pd.DataFrame([[1, 2, 3, 4, 5], [7, 8, 9, 10, 11]], index=['age', 'value']).T
df['groups'] = pd.cut(df.age, [0, 1, 3, 5]) # define bins (0,1], (1,3], (3,5]
df.groupby('groups')['value'].sum()

问题在于groupby只是一个简单的求和,但随着时间的推移,我们需要排除某些值。在这个例子中,您可以看到余额和累计NCO在后期下降。如果我们放出了100k美元的贷款,但它们还没有全部到达90个月的老化期,如果我们将它们全部包括在内,我们将低估90个月的损失比率,因为所有贷款都还没有在第90个月出现违约的机会。谢谢您的回答 :) - Russ W

0

我不确定我完全理解你的逻辑,但是你可以通过pandas的querygroupby的组合来实现sumifs。

示例

import pandas as pd
import numpy as np

age = np.random.randint(85, 100, 50)
balance = np.random.randint(1000, 2500, 50)
nco = np.random.randint(85, 100, 50)

df = pd.DataFrame({'age': age, 'balance': balance, 'nco':nco})


df['reference_age'] = df['age'].apply(lambda x: 5 * round(float(x)/5))

outstanding_balance = (
   df
   .query('age >= reference_age')
   .groupby('reference_age')
   [['balance']]
   .sum()
   .rename(columns={'balance': 'Outstanding Balance'}
   )

cumulative_nco = (
   df
   .query('age < reference_age')
   .groupby('reference_age')
   [['nco']]
   .sum()
   .rename(columns={'nco': 'cumulative nco'})
   .cumsum()
   )


result = outstanding_balance.join(cumulative_sum).T

结果

reference_age            85       90       95
Outstanding Balance  2423.0  16350.0  13348.0
cumulative nco          NaN    645.0   1107.0

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