算法题 - 贷款违约K笔的概率 - Python

189 篇文章 3 订阅
贷款违约K笔的概率

问题描述:

N笔贷款,每笔贷款违约的概率为 [p1、p2、p3 ... ... pn],求恰好有K笔贷款违约的概率。

前提条件:(我自己加的哈)

  • 每笔贷款违约的概率相互独立,且概率值p [0, 1] 范围内。

问题分析:

这是今天头条的第二个面试题,自己想到动态规划来做了,但是,被这个概率计算差点给搞懵逼了,事实说明数学才是其他学科的基础呀。

现在直接给出递推方程式,然后再去解读:

d p [ k ] [ n ] = d p [ k ] [ n − 1 ] ∗ ( 1 − p n ) + d p [ k − 1 ] [ n − 1 ] ∗ p n dp[k][n] = dp[k][n-1] * (1 - p_n) + dp[k-1][n-1] * p_n dp[k][n]=dp[k][n1](1pn)+dp[k1][n1]pn

d p [ k ] [ n ] dp[k][n] dp[k][n] 表示,有n笔贷款时,恰好有k次违约的概率,这个值怎么求那?可以从子问题入手,要想得到这个值,不难发现有两个方向:
(1)dp[k][n-1] 表示有n-1笔贷款时,恰好有k次违约的概率,现在已经恰好k次了,那么新来的那个贷款 p n p_n pn 没有违约就可以继续保持k次了,所以是: d p [ k ] [ n − 1 ] ∗ ( 1 − p n ) dp[k][n-1] * (1 - p_n) dp[k][n1](1pn)

(2)dp[k-1][n-1] 表示有n-1笔贷款时,恰好有k-1次违约的概率,现在是恰好k-1次,那么新来的那个贷款 p n p_n pn 违约了,不就是k次了吗,所以是: d p [ k − 1 ] [ n − 1 ] ∗ p n dp[k-1][n-1] * p_n dp[k1][n1]pn

所以综上所述,就可以得出上面的递推式了: d p [ k ] [ n ] = d p [ k ] [ n − 1 ] ∗ ( 1 − p n ) + d p [ k − 1 ] [ n − 1 ] ∗ p n dp[k][n] = dp[k][n-1] * (1 - p_n) + dp[k-1][n-1] * p_n dp[k][n]=dp[k][n1](1pn)+dp[k1][n1]pn

需要注意的地方是: 边界的处理,也就是k=0n=0的情况,要单独计算。现在看一个例子:

输入数据为: N, K, P = 4, 3, [0.8, 0.9, 0.7, 0.6]

可以得出dp:

在这里插入图片描述

Python3实现:

现在的时间复杂度为O(kn), 空间复杂度为O(kn)

# @Time   :2019/02/12
# @Author :LiuYinxing
# Python3
# 动态规划


class Solution:

    def probabilityK(self, N, P, K):

        if N <= 0 or N < K: return 0

        dp = [[-1] * (N + 1) for _ in range(K + 1)]  # 开辟dp

        # 初始化 dp 边界
        dp[0][0] = 1
        for n in range(1, N+1):  # 上边界
            dp[0][n] = dp[0][n-1] * (1 - P[n-1])

        for k in range(1, K+1):  # 左边界
            dp[k][0] = 0

        for k in range(1, K+1):  # 计算dp
            for n in range(1, N+1):
                dp[k][n] = dp[k][n-1] * (1 - P[n-1]) + dp[k-1][n-1] * P[n-1]

        return dp[-1][-1]  # 返回结果


if __name__ == '__main__':
    solu = Solution()
    N, K = 4, 3
    P = [0.8, 0.9, 0.7, 0.6]
    print(solu.probabilityK(N, P, K))

压缩dp空间(可以结合上图理解)现在的时间复杂度为O(kn), 空间复杂度为O(n)

# @Time   :2019/02/12
# @Author :LiuYinxing
# Python3
# 动态规划,压缩dp空间


class Solution:

    def probabilityK(self, N, P, K):

        if N <= 0 or N < K: return 0

        dp = [-1] * (N + 1)  # 开辟dp

        # 初始化 dp 边界
        dp[0] = 1
        for n in range(1, N+1):  # 上边界(第一行)
            dp[n] = dp[n-1] * (1 - P[n-1])

        for k in range(1, K+1):  # 计算dp
            pre = 0  # 表示 要计算当前值的前一个值
            for n in range(1, N+1):
                temp = pre * (1 - P[n-1]) + dp[n-1] * P[n-1]
                dp[n-1], pre = pre, temp
            dp[N] = pre
        return dp[-1]  # 返回结果


if __name__ == '__main__':
    solu = Solution()
    N, K = 4, 3
    P = [0.8, 0.9, 0.7, 0.6]
    print(solu.probabilityK(N, P, K))

同理,也可以把空间复杂度压缩为O(k)

声明: 总结学习,有问题或不当之处,可以批评指正哦,谢谢。

违约概率(Probability of Default,简称PD)是金融领域中一个重要的概念,通常用于衡量借款人或债务人在未来一段时间内未能履行其财务义务的可能性。在信用评分、贷款审批和风险管理工作等领域有广泛应用。在Python中,可以利用各种统计和机器学习模型来预测违约概率,常见的方法有逻辑回归、随机森林、梯度提升机等。 逻辑回归是一种常用的二分类算法,它通过模型估计出概率值来表示事件发生的可能性。在违约概率预测中,逻辑回归可以用来估计借款人在未来一定期限内违约概率。使用Python中的`sklearn`库,可以很方便地实现逻辑回归模型并进行违约概率的预测。 下面是一个简化的例子,展示了如何使用Python的`sklearn`库来构建逻辑回归模型进行违约概率预测: ```python from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score # 假设df是一个Pandas DataFrame,包含了相关的特征和标签(1表示违约,0表示未违约) X = df.drop('default', axis=1) # 特征变量 y = df['default'] # 标签变量 # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 创建逻辑回归模型实例 log_reg = LogisticRegression() # 训练模型 log_reg.fit(X_train, y_train) # 预测违约概率 y_pred_proba = log_reg.predict_proba(X_test)[:, 1] # 计算AUC分数,评估模型性能 auc_score = roc_auc_score(y_test, y_pred_proba) print('AUC得分:', auc_score) ``` 通过上述代码,我们可以训练一个逻辑回归模型来预测违约概率,并通过AUC分数来评估模型的预测能力。在实际应用中,还需要进行特征选择、模型调优等步骤,并考虑模型的解释性和业务要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值