1. 项目背景及问题定义
1.1 项目背景
P2P网络借贷来源于p2p小额借贷,P2P小额借贷是一种将非常小额度的资金聚集起来借贷给游资净需求人群的一种商业模式,p2p借贷是指不需要以银行等传统金融机构为中介,借贷双方直接通过网络平台交易的无担保借贷、借款人可以以低于银行贷款利息快捷方便借到钱而放款人可以获得高于银行存款的利息。目前国内出现了宜信、拍拍贷、人人贷等网络借贷平台。美国则有Prosper、LendingClub。
1.2 问题定义
本文主要有以下两个目的:一是挖掘违约的客户具有什么特点;二是根据历史数据建立一个预测模型去预测哪些客户有可能违约。
2. 数据准备及预处理
本文所用数据来源于kaggle上的Prosper2005~2014的数据。
2.1 数据预处理
使用shape函数看一下各变量的情况。可以看出共有81个变量,113937条数据。探索各变量的具体含义。
2.1.1 数据变量解释
Variable | Description |
|
ListingKey | 每个列表的唯一键,与API中列表对象中使用的“键”具有相同的值。 | 1 |
ListingNumber | 网站上显示的唯一标识该列表的公众号码。 | 2 |
ListingCreationDate | 表创建时间(可能是交易开始计息时间). | 3 |
CreditGrade | 信用等级,反映的是2009年7月1日前客户的信用级,信用等级越高,其偿债能力越强. | 4 |
Term | 期限,筹资者通过网贷平台进行借款时所承诺的最终偿还期限,借款期限体现该资产的流动性,期限较长的资产应存在着流动性溢价(利率上涨). | 5 |
LoanStatus | 贷款状态(Completed、Current、Defaulted、Chargedoff等) | 6 |
ClosedDate | 关闭日期适用于已取消,已完成,已扣除费用和拖欠贷款状态。 | 7 |
BorrowerAPR | 贷款的借款人年利率(APR)。 | 8 |
BorrowerRate | 借款标利率,作为P2P平台资金借贷价格的代理变量,BorrowerRate不包含其他费用,是筹资者付给投资人的报酬,也是融资最直接和最重要的成本,其体现了资金供求双方在综合考虑各种因素情况下所认可的资金使用成本.
| 9 |
LenderYield | 贷款收益率。 贷款人收益率等于贷款利率减服务费。 | 10 |
EstimatedEffectiveYield | 有效收益等于借款人利率(i)减去服务费率,(ii)减去收取的未收取利息,(iii)加上估计收取的滞纳金。 适用于2009年7月以后发放的贷款。 | 11 |
EstimatedLoss | 估计损失是估计的主要损失。适用于2009年7月以后发放的贷款。 | 12 |
EstimatedReturn | 在创建时分配给上市公司的预计收益。估计收益是估计的有效收益与估计损失率之间的差额。适用于2009年7月以后发放的贷款。 | 13 |
ProsperRating (numeric) | 创建列表时分配的Prosper评级:0 - N / A,1 - HR,2 - E,3 - D,4 - C,5 - B,6 - A,7 - AA。 适用于2009年7月以后发放的贷款。 | 14 |
ProsperRating (Alpha) | 信用等级,反映的是2009年7月1日后的信用等级.信用等级越高,其偿债能力越强. | 15 |
ProsperScore | 使用历史Prosper数据构建的自定义风险评分。 得分从1-10开始,10分是最好的,或者是最低的风险分数。 适用于2009年7月以后发放的贷款。 | 16 |
ListingCategory | 借款人在挂牌时所选择的上市类别:0 -不可用,1 -债务合并,2 -家庭改善,3 -业务,4 -个人贷款,5 -学生使用,6 -自动,7 -其他,8 -婴儿和收养,9 -船,10 -美容程序,11订婚戒指,绿色贷款,13 -家庭开支,14 -大型购买,15 -医疗/牙科,16 -摩托车,17 -右室,18 -税,19 -假期,20 -婚礼贷款 | 17 |
BorrowerState | 贷款人借款地点 | 18 |
Occupation | 贷款人职业 | 19 |
EmploymentStatus | 受雇佣状态(Self-employed、Employed等) | 20 |
EmploymentStatusDuration | 受雇佣状态持续时间(以月为计算单位) | 21 |
IsBorrowerHomeowner | 如果借款人的信用档案中有抵押贷款或提供确认其为房主的文件,则借款人将被归类为房主。 | 22 |
CurrentlyInGroup | 指定在列表创建时借款人是否在一个组中。 | 23 |
GroupKey | 借款人是其成员的小组的关键。 如果借款人没有团体关系,价值将为空。 | 24 |
DateCreditPulled | 信贷资料被扣除的日期。3 | 25 |
CreditScoreRangeLower | 由消费者信用评级机构提供的借款人信用评分范围的下限值。 | 26 |
CreditScoreRangeUpper | 由消费者信用评级机构提供的借款人信用评分范围的上限值。 | 27 |
FirstRecordedCreditLine | 第一条信用额度建立的日期 | 28 |
CurrentCreditLines | 信贷资料被调查时的当前信贷额度。 | 29 |
OpenCreditLines | 调查信贷资料时的未清信用额度。 | 30 |
TotalCreditLinespast7years | 信贷资料在过去七年中的信用额度。 | 31 |
OpenRevolvingAccounts | 开立的循环账户数量。 | 32 |
OpenRevolvingMonthlyPayment | 循环账户(如信用卡)每月还款数量 | 33 |
InquiriesLast6Months | 最近6个月查过多少次征信记录 | 34 |
TotalInquiries | 征信记录查询总次数 | 35 |
CurrentDelinquencies | 当前拖欠额度 |
36 |
AmountDelinquent | 当前拖欠美元数 | 37 |
DelinquenciesLast7Years | 信用资料提交时借款人过去7年违约次数,该指标在一定程度上可以体现借款标发布者的信用状况 | 38 |
PublicRecordsLast10Years | 过去10年的公共记录数量 | 39 |
PublicRecordsLast12Months | 信用状况被抽调时过去12个月的公共记录数量。 | 40 |
RevolvingCreditBalance | 循环账户中的美元 | 41 |
BankcardUtilization | 使用的可用循环信用的百分比。 | 42 |
AvailableBankcardCredit | 通过银行卡的可用信用总额。 | 43 |
TotalTrades | 开设的交易行数 | 44 |
TradesNeverDelinquent | 从未拖欠的交易数量 | 45 |
TradesOpenedLast6Months | 最近6个月内开设的交易数量。 | 46 |
DebtToIncomeRatio | 借款人的债务收入比,债务收入比越高说明筹资者财务状况越差,还款能力较低.其向P2P平台借款时,投资者应要求有更高的回报.如果债务与收入比率不可用,则此值为零。 该值上限为10.01(任何债务收入比率大于1000%将返回为1001%)。
| 47 |
IncomeRange | 贷款人年收入范围 | 48 |
IncomeVerifiable | 借款人表示他们有支持其收入的必要文件。 | 49 |
StatedMonthlyIncome | 客户月收入,月收入越高,投资者对该借款本息按时回流越有信心 | 50 |
LoanKey | 每笔贷款的唯一密钥。 这与在API中使用的密钥相同。 | 51 |
TotalProsperLoans | Prosper在创建此列表时借给他人的贷款数量。 如果借款人没有提前贷款,此值将为空。 | 52 |
TotalProsperPaymentsBilled | 借款人在创建此列表时对Prosper贷款进行的准时付款数量。 如果借款人没有提前贷款,此值将为空。 | 53 |
OnTimeProsperPayments | 借款人在创建此列表时对Prosper贷款进行的按时付款数量。 如果借款人没有提前贷款,此值将为空。 | 54 |
ProsperPaymentsLessThanOneMonthLate | Prosper贷款在创建此列表时迟到不到一个月的借款人的付款数量。 如果借款人没有提前贷款,此值将为空。 | 55 |
ProsperPaymentsOneMonthPlusLate | Prosper贷款在创建此上市时间晚于一个月时支付的借款人数量。 如果借款人没有提前贷款,此值将为空。 | 56 |
ProsperPrincipalBorrowed | 创建上市时借贷Prosper贷款的总本金。 如果借款人没有提前贷款,此值将为空。 | 57 |
ProsperPrincipalOutstanding | 创建上市时,Prosper贷款的主要欠款。 如果借款人没有提前贷款,此值将为空。 | 58 |
ScorexChangeAtTimeOfListing | 借款人的信用评分在信贷资料被提取时发生变化。 这将是相对于借款人上一次Prosper贷款的变化。 如果借款人没有提前贷款,此值将为空。 | 59 |
LoanCurrentDaysDelinquent | 拖欠的天数。 | 60 |
LoanFirstDefaultedCycleNumber | 贷款被取消的周期。如果贷款没有被扣除,价值将是无效的。 | 61 |
LoanMonthsSinceOrigination | 贷款发起后的月数。 | 62 |
LoanNumber | 与贷款相关的唯一数值。 | 63 |
LoanOriginalAmount | 借款人在借款时已经向prosper借入的资金,如果没有历史记录则为0,显然,借入本金越多,其还款压力越大,但是这项指标大的话也可能说明该客户对prosper依赖性较强.
| 64 |
LoanOriginationDate | 贷款发起的日期。 | 65 |
LoanOriginationQuarter | 贷款起源的季度。 | 66 |
MemberKey | 与借款人相关的唯一键。 这是在API成员对象中使用的相同标识符。 | 67 |
MonthlyLoanPayment | 预定的每月贷款支付。 | 68 |
LP_CustomerPayments | 借款人在贷款上的预付款累计总支付。 如果贷款已经收取了费用,这个数值将排除任何回收。 | 69 |
LP_CustomerPrincipalPayments | 借款人在贷款上进行的预借款累计本金付款。 如果贷款已经收取了费用,这个数值将排除任何回收。 | 70 |
LP_InterestandFees | 借款人支付的预付款累计利息和费用。 如果贷款已经收取了费用,这个数值将排除任何回收。 | 71 |
LP_ServiceFees | 已投资贷款的投资者支付的累计服务费。 | 72 |
LP_CollectionFees | 投资于贷款的投资者支付的累计收取费用。 | 73 |
LP_GrossPrincipalLoss | 贷款的总收费金额。 | 74 |
LP_NetPrincipalLoss | 本金仍然未收回. | 75 |
LP_NonPrincipalRecoverypayments | 任何回收付款的利息和费用部分。 目前的付款政策按以下顺序付款:费用,利息,本金。 | 76 |
PercentFunded | 上市资金的百分比。 | 77 |
Recommendations | 在创建列表时借款人的建议数量。 | 78 |
InvestmentFromFriendsCount | 投资贷款的朋友数量。 | 79 |
InvestmentFromFriendsAmount | 由朋友做的投资。 | 80 |
Investors | 为贷款提供资金的投资者数量。 | 81 |
可以看出,数据在2009年7月前后变量有较大不同。因此将数据分为2009年7月1日前后两部分。本文主要是对2009年之后的数据进行分析预测。
使用describe()函数及info()函数快速浏览数据,可以看到我们需要处理以下问题:
- 一些变量存在缺失值。如CreditGrade等。
- 有一部分变量为管理标识符,对构建模型没有任何意义,如ListingKey等。
- 共有17个Object类型变量,需要对它们做一些转换。
- 变量有多种不同的取值,需要进行重新调整。
- 观察是否存在异常值
图 2.1
接下来逐个解决上述问题。
2.1.2 删除无意义变量
为了快速减少变量数量,首先将一些毫无意义的变量及冗余变量删除。
#删除冗余变量
data.drop(["ListingKey", "ListingNumber", "LoanKey", "LoanNumber"], axis=1, inplace=True)
还有其他一些变量可能会提供有用的信息,但需要进行更细致的分析。减少这种会增加不必要的复杂性的变量会更好。
#删除无关变量
data.drop(["ListingCreationDate", "ClosedDate", "DateCreditPulled", "LoanOriginationDate", "LoanOriginationQuarter", "MemberKey"],
axis=1, inplace=True)
同样,有一类变量描述当前贷款的状况或贷款发放的时间。这些变量属于贷后变量,即在贷款发放后才有的,申请时没有,因此这些变量属于未来变量,(例如LoanCurrentDaysDelinquent)与我们无关。
#删除贷后变量
data.drop(["LoanCurrentDaysDelinquent", "LoanFirstDefaultedCycleNumber", "LoanMonthsSinceOrigination", "LP_CustomerPayments",
"LP_CustomerPrincipalPayments", "LP_InterestandFees", "LP_ServiceFees", "LP_CollectionFees", "LP_GrossPrincipalLoss",
"LP_NetPrincipalLoss", "LP_NonPrincipalRecoverypayments"], axis=1, inplace=True)
此时还有60个变量。
2.1.3 处理缺失值
首先先整体查看一下各变量缺失情况。
missing=pd.concat([data.isnull().any(),data.count()],axis=1)
column=['是否缺失','数量']
missing=pd.DataFrame(list(missing.values),index=list(missing.index),columns=column)
max=missing['数量'].max()
missing['缺失数量']=max-missing['数量']
missing['缺失率%']=missing['缺失数量']/max*100
miss=missing[missing['数量']<max]
print(miss)
可以看到,每个变量都存在缺失情况。对于缺失率过大的变量,采取直接删除的方式。否则盲目填充只会给模型引入较大噪声值。本文定义将缺失率大于80%的变量删除。对于缺失率较小的变量,因为缺失数量较少,采取直接删除缺失值的方法。下面对各个变量详细介绍缺失值的处理方式。
- BorrowerAPR
borrower_fees = data["BorrowerAPR"] - data["BorrowerRate"]
borrower_fees.median()
data["BorrowerAPR"].isnull().sum()
data["BorrowerAPR"].fillna(data["BorrowerRate"] + borrower_fees.median(), inplace=True)
- EstimatedEffectiveYield
与上一条类似。
estimated_loss_from_fees = data["BorrowerRate"] - data["EstimatedEffectiveYield"]
estimated_loss_from_fees.median()
data["EstimatedEffectiveYield"].fillna(data["BorrowerRate"] - estimated_loss_from_fees.median(), inplace=True)
- EstimatedLoss
EstimatedLoss损失了25%的值采用中位数填充。
data["EstimatedLoss"].fillna(data["EstimatedLoss"].median(), inplace=True)
- EstimatedReturn
该变量定义为EstimatedEffectiveYield - EstimatedLoss。
data["EstimatedReturn"].fillna(data["EstimatedEffectiveYield"] - data["EstimatedLoss"], inplace=True)
- DebtToIncomeRatio
这个变量的意思是债务收入比。因此我们采用另外两个已知来计算它。
data["DebtToIncomeRatio"].fillna(data["MonthlyLoanPayment"] / (data["StatedMonthlyIncome"] + 1), inplace = True)
- 对于缺失率较小的变量
直接删除缺失值。
data.dropna(subset=["EmploymentStatusDuration", "CreditScoreRangeLower", "FirstRecordedCreditLine", "CurrentCreditLines",
"TotalCreditLinespast7years"], inplace=True)
2.1.4 数值转换
- LoanOriginationDate数据转换
因为数据里2009年7月之前的数据指标与2009年7月之后的不同,因此将其转化为7月前后。
def data_phase(s):
if s>='2009-07-01':
c='After 200907'
else:
c='Before 200907'
return c
data['dataphase']=data['LoanOriginationDate'].apply(data_phase)
- LoanStatus数值转换
我们真正感兴趣的是已完成的贷款与违约贷款。 由于无法判断“Current”贷款是否最终会违约,因此我们不能将其用于分析。 由于贷款尚未偿还,近一半的数据集对我们无用。 为了使我们的最终估计更加精确,简化问题并保留数据,我们假设所有“Past Due”和“Chargedoff”贷款都将变为Defaulted。 因此,我们将留下两个类:“Completed”和“Defaulted”。 我们将这些二进制结果分别编码为1和0。因为Cancelled只有一个,直接删除。
data_historical = data[data["LoanStatus"] != "Current"]
data_historical = data_historical[data_historical["LoanStatus"] != "Cancelled"]
data_historical["LoanStatus"].value_counts()
data_historical["LoanStatus"] = (data_historical["LoanStatus"] == "Completed").astype(int)
查看违约贷款和不违约的比例。
fig = plt.figure()
ax1 = fig.add_subplot(221)
sns.countplot(data_historical["LoanStatus"])
图2.4
因此,在历史数据中,67.43%的贷款已经完成。 “拖欠”贷款的32.57%。在分析过程中,我定义的违约包括撇帐,取消贷款,甚至包括任何迟付的贷款。将0标记为“ 坏“贷款而不是彻头彻尾的”违约“。
2.2 探索数据
2.2.1 贷款者地区分布及对应地区的好账率
图2.5所示是各个州的贷款人数量,可以看出,经济发达的地区借贷人数也相应增多。图2.6是各个州的坏账率。可以看到阿拉斯加州华盛顿等经济发达地区的坏账率较少,而阿拉巴马州等经济落后的地区坏账率较高。
f, ax= plt.subplots(figsize = (11, 8))
ax.set_yticklabels(ax.get_yticklabels())
State=data_historical.BorrowerState
State_counts=State.value_counts()
sns.barplot(x=State_counts.values,y=State_counts.index)
plt.title('BorrowerState')
plt.xlabel('Order Numbers of each State')
plt.ylabel('State in Abbreviation')
plt.show()
plt.savefig("C:/Users/User/Desktop/python图集/1.png")
图2.5
图2.6
2.2.2 申请理由与坏账率
申请贷款的理由与违约率似乎呈现了一定的关系,可以看到房屋贷款的坏账率最低,仅为11.11%,而用于环保类型的贷款坏账率高达56.52%。此外,用于家庭开支及牙科医疗的坏账率也较高。
图2.7
2.2.3 信用分数/等级与坏账情况
信用等级/分数有下列四个指标。具体释义参见表1。可以看到整体的坏账率趋势是随着信用等级提高而递减的,在信用等级11处出现了异常增加。观察到信用分数上限和下限两个指标呈现出的图形非常相似,计算二者相关性,发现高度相关,故删除其中一个变量。
图2.8
2.2.4 雇佣状态与坏账率
EmploymentStatus代表的是职业的类型,比如是个体户、上班族、全职或是兼职等。图可以看到Other的坏账率最高,比较神奇的是兼职的坏账率低于全职的。图则表示持续在职时间长短。图中看不出该变量与坏账率的直接关系。
图2.9
图2.10
2.2.5 收入情况与坏账率
图2.11表示年收入,图表示月收入。可以看出年收入除了不显示及未雇佣以外,整体的坏账率是随着年收入的递增减少的。由月收入的箱线图可知,未出现坏账情况的客户的月收入水平要高于出现坏账情况的。
图2.11
图2.12
2.2.6 债务收入比与坏账率
可以看出,未出现坏账情况的借贷人的债务收入比要低于出现坏账情况的。债务收入比一定程度上可以反映借贷人的还款压力。
图2.13
2.2.7 银行卡可用信用额度及利用率与坏账情况
可以看出未出现坏账情况的客户银行卡可用额度要比出现坏账情况的客户多,可循环使用的银行卡额度利用率则较低,两个指标一定程度上反映了客户的财政状况。
图2.14
2.2.8 是否拥有房屋与坏账率
可以看到,拥有房产的客户的坏账率略低有没有房屋的客户。
图2.15
2.2.9 信用额度与坏账率
有两个指标。一是当前可用信用额,二是过去七年可用信用总额。两个指标没有明显不同。
图2.16
2.2.10 拖欠天数与坏账率
可以看出。出现坏账情况的客户的平均拖欠次数要高于未出现坏账情况的客户。
图2.17
2.2.11 多变量分析
绘制各变量间的相关性热力图。
图2.18
3. 构建模型
3.1 特征选择
根据前文的分析,删除了部分无用及高度相关的变量,此时还有36个变量。后面我们会用PCA进行降维处理。
3.2 划分测试集
按照训练集与测试集7:3的比例对数据进行划分
X = after2009.drop("LoanStatus", axis=1)
y = after2009["LoanStatus"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
3.3 数据处理
对连续数值变量进行归一化。归一化将各范围不同的数值变量统一处理至0-1区间,能够消除各变量取值范围不同给模型带来的影响。
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
3.4 降维处理
使用PCA进行单变量特征选择,并将变换后的数据保存到新变量中,通过不同数量的变量查看维度的进一步降低是否对准确性或拟合性能产生正面影响。分别保留10个特征和15个特征。
pca = PCA(n_components=10)
pca.fit(X_train_scaled)
X_train_pca10 = pca.transform(X_train_scaled)
X_test_pca10 = pca.transform(X_test_scaled)
pca.explained_variance_ratio_
pca = PCA(n_components=15)
pca.fit(X_train)
X_train_pca3 = pca.transform(X_train_scaled)
X_test_pca3 = pca.transform(X_test_scaled)
pca.explained_variance_ratio_
3.4 建立模型
训练分类器之前,首先考虑哪些指标能够量化不同分类器性能。虽然从一般意义上讲,我们试图准确预测(或分类)哪些贷款将成为坏账,哪些贷款将全部偿还,但真正的目标是尽可能减少会成为坏账的贷款。因此,我们的目标实际上是尽可能多地将坏账分类正确,即使这意味着偶尔将未坏账的贷款分类为坏账。即使以精确性为代价,也要使坏账分类实现最大化召回。召回率将成为最相关的指标。
本文使用几种训练数据(原始数据,归一化数据和降维后的数据等)来训练朴素贝叶斯、逻辑回归、随机森林这三种分类器。
3.5 模型评估
采用之前分割的测试集来验证模型的泛化能力。评价指标为召回率及acc。各指标数据如下:
总体准确度(acc) | 召回率 | |
Gaussian Naive Bayes | 0.604013 | 0.668128 |
Gaussian Naive Bayes (PCA: 10 components) | 0.687233 | 0.233174 |
Gaussian Naive Bayes (PCA: 15 components) | 0.632494 | 0.478980 |
Gaussian Naive Bayes (scaled data) | 0.675218 | 0.751511 |
Logistic Regression | 0.708048 | 0.214386 |
Logistic Regression (PCA: 10 components) | 0.700067 | 0.168705 |
Logistic Regression (PCA: 15 components) | 0.695958 | 0.000000 |
Logistic Regression (scaled data) | 0.708831 | 0.224810 |
Random Forest Classifier | 0.684143 | 0.404967 |
Random Forest Classifier (PCA: 10 components) | 0.662389 | 0.386824 |
Random Forest Classifier (PCA: 15 components) | 0.673383 | 0.394159 |
Random Forest Classifier (scaled data) | 0.782617 | 0.735737 |
可以看到,各个模型的召回率都不是很高,只有使用归一化后数据的朴素贝叶斯的模型召回率达到了75%。同时,使用归一化后数据训练的随机森林模型召回率为73%,acc为78%。其中,使用降维至15个特征的数据的Logistic回归。它的准确度得分为0.6742,但在精度和召回率方面均为0。这个模型是无效的,它只是将所有贷款都分类为不会坏账的贷款得出结果67%。这是由于类别数据相差过大造成的。分类样本不均衡导致的模型问题暂时搁置,留待日后深入探究。
4.参考文献
网贷平台prosper贷款数据分析
http://statistics.berkeley.edu/sites/default/files/tech-reports/666.pdf网贷平台Prosper2005~2014贷款数据分析(一)