最近在看《Python编程导论》(第二版), 看到类那一章时,后面有个对比几种不同类型贷款的例子,有一天在回看时,突然发现,这不就是一种量化的方式么?之前本来是草草地一带而过,现在又来了兴趣,打算仔细研究研究。

注:本文对书中原有的代码基本不做改动,主要通过注释的方式进行说明,并增加了另一种贷款方式进行比较,旨在帮助大家对代码做进一步分析。

 
一、什么是是量化?
“量化”从字面上可以理解为数量化,如果应用在投资领域上的话,简单的说,就是将每一种投资产品,通过数据分析的方式,将其特点(风险、潜力等等)用详细的数据反映出来,更好地指导投资者获取稳定收益。
其实现在很多金融产品都是非常复杂的,普通投资者没点金融常识根本看不懂。不会计算产品的实际收益,看不到潜在的风险,很容易就被套住了。所以,如果有量化分析的经验,就可以对产品有比较清楚的了解。
好了,先来看看书中描述几种贷款方式吧:
1.每月偿还固定金额的贷款(简称等额本息贷款);
2.先还一笔固定点数(百分比)的贷款,然后每月再以较低的利率还款(简称固定点数贷款);
3.先以较低的利率还款,满x个月后再以较高的利率还款(简称双利率贷款)。
二、简述各种贷款类型
1.等额本息贷款
在查等额本息的概念时,发现还有一种叫做等额本金的贷款方式也会被经常用到,下面将依次做介绍。
等额本息:根据固定的还款时间,计算出应还的总利息,再加上本金,然后每个月平均等额的还款。
根据贷款总额loan、月利率r及还款时间m(月),可以推导出每个月的还款金额。
假设每月固定还款X,则每月的还款情况如下:
月数 | 每月剩余欠款
0 | loan
1 | loan*(1 + r) - X
2 | [loan*(1 + r) - X] * (1 + r) - X => loan*(1+r)^2 - X*(1+r) -X
3 | [loan*(1+r)^2 - X*(1+r) -X]*(1+r) - X => loan*(1+r)^3 - X*(1+r)^2 -X*(1+r) -X
... ...
n | loan*(1+r)^n - X*(1+r)^(n-1) -X*(1+r)^(n-2) - ... -X(1+r)^0
当n=m时,欠款为0,即:
loan*(1+r)^m - X*(1+r)^(m-1) - X*(1+r)^(m-2) - ... - X(1+r)^0 = 0
观察等号左边,不看第一项,提取其余多项式的-X公约数后,发现其实是一个首项a1为1, q=1+r,项数为m的等比数列,根据等比数列的求和公式Sn = a1*(1 - q^n)/(1 - q) 得:
loan*(1+r)^n - X[(1+r)^0 + (1+r)^1 + ... + (1+r)^(m-1)] = 0
loan*(1+r)^n -X*(1-(1+r)^m) / (-r) = 0
即:
loan*(1+r)^n = X*[(1+r)^m-1]/r
所以得到:
X = loan*r*(1+r)^n/[(1+r)^m-1]
那么针对等额本息的还款方式,我们就可以用Python写一个专门的函数,这样就不用每次计算的时候都把这个公式推导一遍了:
def findPayment(loan, r, m):# 计算在贷款额loan 月利率r和期限m个月下,每月需返还的固定金额return loan * ((r * (1 + r) ** m) / ((1 + r) ** m - 1))

这样,每次在计算等额本息贷款的每月还款金额时,只需要将贷款总额loan, 月利率r和还款总月数m代入此函数中,就能得出结果了。
 
2.等额本金贷款
等额本金相对来说要简单一些,每月所还的本金是相同的,利息由每个月的剩余本金计算得出。
第n个月需还的金额:(loan/m) + (loan - n * loan/m) * r
 
3.固定点数贷款
按照定义,我们在首次还款时先按固定的点数还一部分贷款,然后再按较低的利率还完剩余的贷款。
 
4.双利率贷款
前x个月以较低的r1利率还款,后m-x个月以较高的r2利率还款(假设还款总月数为m)。
三、编写与贷款相关的类及子类
我们研究的贷款类型一共有4种(书中的3种+等额本金贷款),所以最好的办法是先定义一个贷款大类,里面包含贷款的基本属性,然后根据各种类型贷款的不同,再定义不同的子类。具体过程如下:
class Mortgage(object):# 构建贷款类, 定义四种贷款都有的属性def __init__(self, loan, annRate, months):self.loan = loan    # 贷款总额self.rate = annRate / 12    # 将年利率转化为月利率self.months = months    # 还款月数self.paid = [0.0]   # 已支付金额self.outstanding = [loan]    # 剩余本金self.payment = findPayment(loan, self.rate, months)    # 每月还款金额, 默认按照等额本息的方式self.legend = None    # 贷款描述def makePayment(self):# 还款函数,调用此函数进行还款self.paid.append(self.payment)reduction = self.payment - self.outstanding[-1] * self.rate    # 还款金额中的本金self.outstanding.append(self.outstanding[-1] - reduction)    # 记录剩余本金def getTotalPaid(self):# 返回已支付贷款总额return sum(self.paid)def __str__(self):# 返回贷款描述return self.legend

class Fixed(Mortgage):
# 等额本息子类
# 只需继承Mortgage(),重写描述属性self.legend即可def __init__(self, loan, r, months):Mortgage.__init__(self, loan, r, months)self.legend = "等额本息, " + str(round(r * 100, 2)) + '%'

def totalCapitalPayment(loan, months, r):
# 等额本金类贷款每个月要还的本金不变,而利息是随着还款月数的增加而减少的,所以定义一个函数,直接返回一个包含每月还款金额的列表即可total = []for m in range(months):total.append(loan / months + (loan - m * (loan / months)) * r)return totalclass FixedCapital(Mortgage):# 等额本金子类def __init__(self, loan, r, months):Mortgage.__init__(self, loan, r, months)# self.payment =capitalPayment(loan, r, months)self.capital = loan / monthsself.total = totalCapitalPayment(loan, months, self.rate)self.legend = "等额本金, " + str(round(r * 100, 2)) + '%'def makePayment(self, m):# 由于等额本金的每月还款额与当前还款月数相关,所以引入还款月数mself.paid.append(self.total[m])# 本期剩余本金 = 上期剩余本金 - 每月固定本金self.outstanding.append(self.outstanding[-1] - self.capital)

class FixedWithPts(Mortgage):# 固定点数子类def __init__(self, loan, r, months, pts):Mortgage.__init__(self, loan, r, months)self.pts = pts    # 固定点数# 计算第一次按照固定点数还款的金额self.paid = [self.loan * (self.pts / 100)]self.legend = "固定点数, " + str(round(r * 100, 2)) + '%, ' + str(pts) + ' points'

class TwoRate(Mortgage):# 双利率子类def __init__(self, loan, r, months, teaserRate, teaserMonths):Mortgage.__init__(self, loan, teaserRate, months)self.teaserMonths = teaserMonths    # 前期低利率月数self.teaserRate = teaserRate    # 前期低利率self.nextRate = r / 12    # 后期高利率self.legend = '双利率, ' + str(teaserRate * 100) + '% for ' + str(self.teaserMonths) + ' months, then ' + \str(round(r * 100, 2)) + '%'def makePayment(self):# 如果到达teaserMonths,则使用self.nextRate高利率,后面每月的付款金额按照剩余本金、利率和月数重新计算if len(self.paid) - 1 == self.teaserMonths:self.rate = self.nextRateself.payment = findPayment(self.outstanding[-1], self.rate, self.months - self.teaserMonths)Mortgage.makePayment(self)    # 未到达teaserMonths时,每月的还款金额

然后再定义一个比较各类贷款的函数,打印出各自的总还款额:
def compareMortgages(amt, years, fixedRate, pts, ptsRate, lowRate, highRate, lowMonths):# 比较各类贷款的总还款额totMonths = years * 12fixed1 = Fixed(amt, fixedRate, totMonths)fixed2 = FixedCapital(amt, fixedRate, totMonths)fixed3 = FixedWithPts(amt, ptsRate, totMonths, pts)twoRate = TwoRate(amt, highRate, totMonths, lowRate, lowMonths)morts = [fixed1, fixed3, twoRate]    # 先对除等额本金外的其他三类贷款进行还款for m in range(totMonths):for mort in morts:mort.makePayment()fixed2.makePayment(m)    # 单独调用包含参数m的等额本金还款参数morts.insert(1, fixed2)    # 还款完毕后再加入贷款列表# 展示四种贷款方式各自的还款总额for m in morts:print(m)print(" Total payments = $" + str(int(m.getTotalPaid())))# 带入实际的值进行比较:
compareMortgages(200000, 30, 0.07, 3.25, 0.05, 0.045, 0.095, 48)

  

# 比较结果
Fixed, 7.0%
Total payments = $479017
Fixed Capital, 7.0%
Total payments = $410583
Fixed, 5.0%, 3.25 points
Total payments = $393011
4.5% for 48 months, then 9.5%
Total payments = $551444

从比较结果可以看出,还款总额从高到低依次为:

双利率 >  等额本息 > 等额本金 > 固定点数

四、使用pylab定义绘制还款曲线函数
只看还款总额还分析地不够彻底,可以通过绘制曲线的方式直观地比较这几种贷款,哪个最划算(或者哪个最坑),所以可以按照每月还款额、还款总额、剩余本金、支付的总利息这几个维度进行分析。
在Mortgage()类中分别添加统计这些信息的函数:
def plotPayments(self, style):
# 统计每月还款额pylab.plot(self.paid[1:], style, label=self.legend)def plotTotPd(self, style):
# 统计每月还款总额totPd = [self.paid[0]]for i in range(len(self.paid)):totPd.append(totPd[-1] + self.paid[i])pylab.plot(totPd, style, label=self.legend)def plotBalance(self, style):
# 统计每月剩余本金pylab.plot(self.outstanding, style, label=self.legend)def plotNet(self, style):# 统计每月支付总利息totPd = [self.paid[0]]for i in range(1, len(self.paid)):totPd.append(totPd[-1] + self.paid[i])# 先通过数组计算出每月偿还的本金(贷款总额 - 每月剩余本金)equityAcquired = pylab.array([self.loan] * len(self.outstanding)) - pylab.array(self.outstanding)# 再用每月的总还款额 - 每月偿还本金 = 每月偿还利息net = pylab.array(totPd) - equityAcquiredpylab.plot(net, style, label=self.legend)

为了能够绘制出这些曲线,我们还需要定义一个绘图函数,并且设置标题、标签等属性,让每个图都更加美观:
def plotMortgages(morts, amt):def labelPlot(figure, title, xLabel, yLabel):pylab.figure(figure)        # 指定当前图,即绘制前要先指定图的figure值pylab.title(title)          # 设置标题pylab.xlabel(xLabel)        # 设置x轴标签pylab.ylabel(yLabel)        # 设置y轴标签pylab.legend(loc='best')    # 将描述信息放在不与曲线冲突的最合适区域styles = ['k-', 'k-.', 'k:', 'b-']              # 设置各类贷款对应的曲线样式payments, cost, balance, netCost = 0, 1, 2, 3   # 设置图的figure,对各类曲线按照指标分类for i in range(len(morts)):pylab.figure(payments)              # 根据figure值,将各类曲线绘制到对应的图中morts[i].plotPayments(styles[i])    # 月还款额pylab.figure(cost)morts[i].plotTotPd(styles[i])       # 总还款额pylab.figure(balance)morts[i].plotBalance(styles[i])     # 剩余本金pylab.figure(netCost)morts[i].plotNet(styles[i])         # 月支付利息labelPlot(payments, '贷款' + str(amt) + '元的每月还款情况', '月数', '月还款金额')labelPlot(cost, '贷款' + str(amt) + '元的还款总额', '月数', '已支付金额')labelPlot(balance, '贷款' + str(amt) + '元的每月本金剩余情况', '月数', '剩余未还本金')labelPlot(netCost, '贷款' + str(amt) + '元的累计利息支付情况', '月数', '支付的累计利息')

最后在比较函数compareMortgages()函数中进行调用即可:
def compareMortgages(amt, years, fixedRate, pts, ptsRate, lowRate, highRate, lowMonths):# 比较各类贷款的总还款额totMonths = years * 12""" ... 此处省略前面的部分代码 ... """# for m in morts:#     print(m)
#     print(" Total payments = $" + str(int(m.getTotalPaid())))
# 展示四种贷款方式的对比曲线plotMortgages(morts, amt)pylab.show()

  

注: 第一次运行时,图像上的中文可能会不显示,这是因为默认字体不是中文,在代码开头导入matplotlib包并做相关设置即可:
import matplotlib
# 修改默认字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['font.family'] = 'sans-serif'

  

五、分析各类曲线
最后我们得到了4张反应贷款各个指标的分析图:
1.每月还款额的变化:

可以看出,等额本息和固定点数从始至终都维持着恒定的还款金额,但是由于固定点数提前还了一部分的贷款,所以后期支付的金额就会少一些;

等额本金是唯一一个利率呈负增长的贷款,因为每月的还款额与剩余本金息息相关,所以一开始支付的金额是最高的,但利息会随着本金的不断减少,到了最后一个月,甚至只还了558块多。适合贷款前期有充裕的钱进行还款的人群;
双利率虽然前48个月的还款额最低,但是后面的300多个月,都不得不付给银行高额的贷款。
 
2.整个贷款周期的本金+利息总和:

该图反映了总还款额随时间变化的情况。如果对比最后贷款结束时的还款金额,很明显,固定点数 < 等额本金 < 等额本息 < 双利率。

而在整个还款过程中,总还款额的增长速率也并非一直不变。例如,除了等额本息和固定点数外(每月还款数固定),等额本金的增长幅度是先快后慢(曲线是一段弧线);而双利率的模式则是先慢后快,有一个明显的拐点。用前期很少的还款额做诱饵,引诱借款人最终偿还高达551444元的高额贷款(别紧张,你没有看错,200000元的本金+351444元的利息)。
 
3.剩余未还本金的情况:
因为4类贷款的本金都是200000万,所以起点是相同的。曲线越陡峭,则说明,本金的还款速度越快;曲线越平滑,就说明可能每个月给银行还的钱大部分都用来付利息了。
 
4.每月累计支付的利息情况:
大体上都呈抛物线,可以看到,即使最划算的固定点数模式的贷款,在经历了30年后,也不得不支付高达193011元的利息,基本上已经跟本金差不多了。所以,这就是银行用复利在赚很多借款人的钱。而大部分人可能还觉得,这样的还款方式好像还OK,但是如果经过了这样量化分析后,感觉还是挺吓人的,所以没事还是少贷款吧。
六、结语
通过这样一步步的分析,我们在了解了这些贷款的各种信息后,同时也提高了自己的编码能力和数据分析的能力,简直是一举三得~这本书中还有一些其他很有意思的问题,涉及面很广,有兴趣的同学可以做深入研究。

转载于:https://www.cnblogs.com/dev-liu/p/python_analysis_loan.html

对几种常见贷款进行数据分析相关推荐

  1. 七种常见的数据分析法之:可行域分析

    导读 福格模型的触发有效区,我们就将其称之为可行域.那么,可行域分析该怎么用呢? 大数据产业创新服务媒体 官网 | www.datayuan.cn 今日头条丨一点资讯丨腾讯丨搜狐丨网易丨凤凰丨阿里UC ...

  2. 七种常见的数据分析方法拆解

    数据分析一直是互联网人辨别方向的不二法门,我们通过对数据的观测来判断事物的发展趋势,也常常利用数据的思维来辩证的为决策做参考. 下面就给大家详细拆解七种常见的数据分析法,让我们的数据分析少走弯路. 0 ...

  3. 几种常见的数据分析方法拆解

    数据分析一直是我们互联网人辨别方向的不二法门,我们通过对数据的观测来判断事物的发展趋势,也常常利用数据的思维来辩证的为决策做参考. 掌握技能和工具只是第一步,做好数据分析还必须要有数据分析思维.数据思 ...

  4. 机器学习中用到的概率知识_山顶洞人学机器学习之——几种常见的概率分布

    机器学习是实现人工智能的重要技术之一.在学习机器学习的过程中,必须要掌握一些基础的数学与统计知识.之前的两篇文章我们分别讲述了中心极限定理与大数定律,它们是数据分析的理论基础.今天我们来介绍几种常见的 ...

  5. python sns绘制回归线_【干货!】用Python演绎5种常见可视化视图

    - 点击上方"中国统计网"订阅我吧!- 通过本篇文章,你将学到: 视图的分类,从哪些维度进行分类 5种常见视图的概念,以及如何在Python中进行使用,都需要用到哪些函数. 注意: ...

  6. 为何大量网站不能抓取?爬虫突破封禁的6种常见方法

    为何大量网站不能抓取?爬虫突破封禁的6种常见方法 在互联网上进行自动数据采集(抓取)这件事和互联网存在的时间差不多一样长.今天大众好像更倾向于用"网络数据采集",有时会把网络数据采 ...

  7. 10种常见的回归算法总结和介绍

    线性回归是机器学习中最简单的算法,它可以通过不同的方式进行训练. 在本文中,我们将介绍以下回归算法:线性回归.Robust 回归.Ridge 回归.LASSO 回归.Elastic Net.多项式回归 ...

  8. [数据分析干货]四种简单常用的数据分析方法,学完立马升职加薪!

    你是否做了N个渠道推广,却不知道钱花的效果怎么样? 你是否用数据做了很多图表,但是只知道表象却不会深入分析现象背后发生了什么,得不出什么有效的结论? 今天就来给大家分享4种最常用的数据分析方法,让你在 ...

  9. 电池管理系统(BMS)功能与作用/BMS 故障分析方法/15种常见故障案例分析

    提示:本篇文章仅供学习参考 文章目录 一.电池管理系统(BMS)功能与作用 二.BMS 故障分析方法 三.15种常见故障案例分析 一.电池管理系统(BMS)功能与作用 从整车角度,电池管理系统(BMS ...

最新文章

  1. 用GPIO口模拟串口通信,它真的来了
  2. NG Updata(升级)
  3. CSS3实现圆角效果
  4. AcWing 841. 字符串哈希(字符串Hash)
  5. 关于net2.0里面新出现的类backgroundworker的应用
  6. mysql-备份和还原(普通还原和binlog还原)
  7. 按照某列属性拆分Excel文件
  8. 拓端tecdat|互联网热门职位薪资对比报告
  9. 监听下拉框,当前选中值
  10. 【语音识别】基于matlab功率谱和倍频法男女生识别【含Matlab源码 705期】
  11. postSQL安装和GIS数据导入
  12. SpringSecurity视频教程
  13. DBF文件初步了解(二)——DBF数据导出代码实现
  14. 微搭低代码Tab栏组件使用指南
  15. 加载大图片,内存溢出问题
  16. 搭建商城系统怎么选择合适的运营模式?
  17. (亲测很实用)地理位置批量转经纬度,基于百度地图api
  18. 正确使用数字化仪前端信号调理功能
  19. 向企业微信发送文字、图片的接口【亲测有效】
  20. 涉密信息系统集成资质申请单位提交材料清单

热门文章

  1. java 图像识别 头部,翻拍识别示例_图像识别 Image_SDK参考_使用SDK(Java)_华为云...
  2. CAD机械设计数字化管理,项目决策快人一步
  3. 博物馆RFID出入库管理系统解决方案--RFID出入库-文物仓库管理-新导智能
  4. Windows 7 64位 HookApi例子
  5. C语言编程对一个逆波兰式进行求值,算式与逆波兰式
  6. clickhouse集群表删除_Clickhouse 分布式表本地表
  7. [ACTF2020 新生赛]Upload 1
  8. 海南电信公网固定IP申请及ICP备案过程
  9. 微型计算机的由来思维导图,央视专访:思维导图的由来!看发明人博赞先生怎么说~...
  10. VueJS 的VNode