一、目录
文章分为以下几个内容项目介绍
数据准备
数据处理
构建模型
总结
二、项目介绍
本项目分析P2P平台Lending Club的贷款数据,Lending Club的背景可参照以下链接:娜姐的学习录:Lending Club贷款数据分析背景介绍zhuanlan.zhihu.com
主要分析以下两个问题:了解P2P平台的业务特点、产品类型、资产质量、风险定价?
有什么建议?
三、数据准备数据下载地址:https://www.lendingclub.com/info/download-data.actionwww.lendingclub.com开发样本与验证样本选择在保证建模数据量的前提下,建模样本尽量选择距离当前时间较近的可用数据。因为如果距离当前时间较长的话,客户群体可能发生变化,社会环境、市场也有可能发生变化。缩短模型迭代周期。开发样本期间:2017年第3、4季度(7月~12月),2018第1季度的数据
验证样本区间:2018年第2季度(4月~6月)
本次开发样本总共有349219条数据;验证样本数据有130733条数据,所以我们的数据量还是比较大的。
四、数据处理
第一步,导入包
import pandas as pd
import numpy as np
import matplotlib as mp1
import matplotlib.pyplot as plt
#plt.style.use('ggplot') #风格设置近似R这种的ggplot库
import seaborn as sns
sns.set(context='notebook',style='ticks',palette="GnBu_d",font_scale=1.5,font='ETBembo',rc={"figure.figsize": (10, 6)})
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
from pyecharts import Pie
pd.set_option('precision',5)#设置精度
pd.set_option('display.float_format', lambda x: '%.5f' % x)#为了直观的显示数字,不采用科学计数法
pd.options.display.max_rows = 200 #最多显示200行
第二步,合并文件
lcvs=[]
lcvs.append(pd.read_csv('E:/chenln/Documents/python/ch3/project/LoanStats_2017Q3.csv',skiprows=0,header=1))
lcvs.append(pd.read_csv('E:/chenln/Documents/python/ch3/project/LoanStats_2017Q4.csv',skiprows=1))
lcvs.append(pd.read_csv('E:/chenln/Documents/python/ch3/project/LoanStats_2018Q1.csv',skiprows=1))
file=pd.concat(lcvs)
#三季度合并的文件写入到prj.csv
file.to_csv('E:/chenln/Documents/python/ch3/project/prj.csv',index=False)
第三步,将准备好的数据读入Pandas
data=pd.read_csv('E:/chenln/Documents/python/ch3/project/prj.csv',encoding="ISO-8859-1")
#使用shape方法查看数据行数及列数
data.shape
(349219, 145)
'''使用head()方法默认查看前5行数据,另外还有tail()方法是默认查看后5行,当然可以输入整数作为参考自定义查看行数'''
data.head(3)
data.info()
#共有145个变量,38个是object类型
RangeIndex: 349219 entries, 0 to 349218
Columns: 145 entries, id to settlement_term
dtypes: float64(107), object(38)
memory usage: 386.3+ MB
首先对于object这类非数值变量,pandas的describe方法会给出变量的:‘非空值数量’、‘unique数量’、‘最大频数变量’、‘最大频数’,
为了直观的观测缺失情况,后面添加了‘缺失值比重’
data.select_dtypes(include=['O']).describe().T\
.assign(missing_pct=data.apply(lambda x : (len(x)-x.count())/len(x)))
从图表中可以得到部分信息:
1.贷款共7个等级,占比最多的是B级
2.还款的形式有两种,占比最多的是36个月
3.贷款人中大多数人工龄10+年
第四步,数据处理
(1) 缺失值处理
percent_count = len(data)/10 # 设定阀值,90%
data = data.dropna(thresh = percent_count, axis = 1 ) #若某一列数据缺失的数量超过阀值就会被删除
data.to_csv('E:/chenln/Documents/python/ch3/project/loans_pro.csv', index = False) # 将预处理后的数据转化为csv
data=pd.read_csv('E:/chenln/Documents/python/ch3/project/loans_pro.csv',encoding="ISO-8859-1")
data.shape
#经过初步处理,变量由145个减少到120
(349219, 120)
#按缺失值比例从大到小排列
data.isnull().sum(axis=0).sort_values(ascending=False)/float(len(data))
对于缺失值处理,各种资料给出很多方法,包括:直接舍弃(一般缺失值占比较多的)
均值,中位数,众数等填充法(一般缺失值占比较少的),或者填充0
用上下数据进行填充
插值法(拉格朗日插值法)
机器学习算法拟合或预测缺失值(如使用随机森林进行缺失值预测)
关于缺失值的处理,我们分以下2种情况:
1)针对缺失值比例10%的以上的变量,我们结合实际业务变量含义,
对缺失比例较大的变量的缺失值进行处理999填充处理或者均值填充处理。
# 缺失比例较大的变量的缺失值处理
values = {'sec_app_revol_util': 999,
'verification_status_joint': 999,
'revol_bal_joint': 999,
'annual_inc_joint': 999,
'sec_app_collections_12_mths_ex_med': 999,
'sec_app_chargeoff_within_12_mths': 999,
'sec_app_num_rev_accts': 999,
'sec_app_open_act_il': 999,
'sec_app_open_acc': 999,
'sec_app_mort_acc': 999,
'sec_app_inq_last_6mths': 999,
'sec_app_earliest_cr_line': 999,
'dti_joint': 999,
'mths_since_last_record': 999,
'mths_since_recent_bc_dlq': 999,
'mths_since_last_major_derog': 999,
'mths_since_recent_revol_delinq': 999,
'mths_since_last_delinq': 999,
'next_pymnt_d': 999,
'il_util': 999,
'mths_since_recent_inq': 999
}
data.fillna(value=values,inplace = True)
2)针对缺失比例低于10%的变量,考虑到我们建模数据量还是比较大的,我们采取直接删除含任意缺失值的记录。
data.shape
(349219, 120)
data = data.dropna(axis = 0, how='any')
data=data.reset_index(drop=True)
data.shape
(291736, 120)
删除含任意缺失值的记录后,我们的数据量从34.9万条变为29.1万条,删除了约5万条含缺失值的记录。
(2) 数据清洗-异常值处理
从分析目的出发,将从原始数据中挑选出一些变量进行分析
analysis_columns=['issue_d','term','int_rate','grade','home_ownership','verification_status',
'purpose','loan_amnt','total_pymnt','out_prncp',
'total_rec_int','total_rec_prncp','installment',
'annual_inc','dti','addr_state','open_acc','loan_status',
'delinq_amnt','acc_now_delinq','tot_coll_amt','emp_length']
analysis_data = data[analysis_columns]
删除特征变量值结尾多余的字符,比如'year','years','%',' ','months','xx'等;
def del_str_process(data):
data['term'] = data['term'].str.replace('months',' ').str.strip().astype('float64')
data['int_rate'] = data['int_rate'].str.replace('%',' ').str.strip().astype('float64')
data['emp_length'] = data['emp_length'].str.replace('< 1 year','0').str.replace('10+ years','11').str.replace('n/a','-1').str.strip()
data['emp_length'] = data['emp_length'].str.replace('years',' ').str.replace('year',' ').str.strip()
data['emp_length'][data['emp_length'] == '10+'] = 11
data['emp_length'] = data['emp_length'].astype('float64')
data['issue_d'] = pd.to_datetime(data['issue_d'])
data['annual_inc'] = data['annual_inc'].astype('float64') # 未核实的年收入(本来就是数值型)
return data
analysis_data = del_str_process(analysis_data)
#analysis_data.head()
好坏定义如下:
Bad: Late (31-120 days) , Charged Off(坏账)
Indeterminate: Late (16-30 days) ,In Grace Period (处于宽限期)
Good: Current, Fully Paid(结清)
def coding(col, codeDict):
colCoded = pd.Series(col, copy=True)
for key, value in codeDict.items():
colCoded.replace(key, value, inplace=True)
return colCoded
#把贷款状态LoanStatus编码为违约=1, 正常=0, 表现期:2:
pd.value_counts(analysis_data["loan_status"])
analysis_data["loan_status"] = coding(analysis_data["loan_status"], {'Current':0,
'Fully Paid':0,
'Late (31-120 days)':1,
'Charged Off':1,
'Late (16-30 days)':2,
'In Grace Period':2,
'Default': 2})
print( '\nAfter Coding:')
pd.value_counts(analysis_data["loan_status"])
After Coding:
0 274570
1 12921
2 4245
Name: loan_status, dtype: int64
第五步,构建模型
单变量分析
1.贷款状态分布
analysis_data["loan_status"].value_counts().plot.pie(autopct='%1.2f%%',figsize=(5, 5))
从图中可以看出,平台贷款发生违约的数量占少数。贷款正常状态占比为94.12%。贷款状态将作为我们建模的标签
2.贷款金额分布
plt.figure(figsize=(10, 5))
sns.set()
sns.set_context("notebook", font_scale=1, rc={"lines.linewidth":2 } )
sdisplot_loan = sns.distplot(analysis_data['loan_amnt'] )
plt.xticks(rotation=90)
plt.xlabel('Loan amount')
plt.title('Loan amount\'s distribution')
sdisplot_loan.figure.savefig("Loan_amount")
贷款金额最小值为1,000美元,最大值为40,000美元,
贷款金额主要集中在10,000美元左右,中位数为12,000美元,
可以看出平台业务主要以小额贷款为主。贷款金额越大风险越大。
3.贷款期限分布
analysis_data["term"].value_counts().plot.pie(autopct='%1.2f%%',figsize=(5, 5))
平台贷款产品期限分为36个月和60个月两种,其中贷款期限为60个月的贷款占比为30.03%,贷款期限为36个月的贷款占比为69.97%。
一般来说贷款期限越长,不确定性越大,违约的可能性更大,期限较长的贷款产品风险越高 。从期限角度看,平台风险偏小的资产占大部分。
4.贷款产品用途种类比较
analysis_data['purpose'].value_counts()# 按借款用途统作统计
debt_consolidation 156286
credit_card 61824
other 24041
home_improvement 21931
major_purchase 8081
medical 4571
small_business 3576
car 3536
house 3086
vacation 2340
moving 2285
renewable_energy 176
wedding 2
educational 1
Name: purpose, dtype: int64
plt.figure(figsize=(8, 4))
sns.set()
sns.set_context("notebook", font_scale=1.5, rc={"lines.linewidth": 2.5})
total = float(len(data.index))
ax = sns.countplot(x="purpose", data=analysis_data, palette="Set2")
ax.set(yscale = "log")
plt.xticks(rotation=90)
plt.title('Purpose')
plt.show()
ax.figure.savefig("Purpose")
P2P平台贷款用途最多的为债务重组(借新债还旧债),其次是信用卡还款,第三是Other。 一般来说,贷款用途为债务重组和信用卡还款的客户现金流较为紧张, 此类客户也是在传统银行渠道无法贷款才转来P2P平台贷款,这部分客户的偿还贷款能力较弱,发生违约的可能性较高。用途为Other的贷款,需要通过其他维度来分析其风险。
5.客户信用等级占比
analysis_data["grade"].value_counts().plot.pie(autopct='%1.2f%%',figsize=(10, 10))
Lending Club平台对客户的信用等级分7类,A~G,信用等级为A的客户信用评分最高,信用等级为G的客户最低,信用等级的客户发生违约的可能性更低。目前,平台客户信用等级占比较多的客户为B类,其次是C类和A类,三者合计占比为81.12%。此外信用等级为E、F、G类的客户占比为5.42%。可以看出Lending Club授信部门对申请人的资信情况把关较严。
6.贷款利率种类分布
analysis_data.describe()
plt.figure(figsize=(18, 9))
sns.set()
sns.set_context("notebook", font_scale=1, rc={"lines.linewidth":2 } )
sdisplot_loan = sns.distplot(analysis_data['int_rate'] )
plt.xticks(rotation=90)
plt.xlabel('Interest Rate')
plt.title('Interest Rate\'s distribution')
sdisplot_loan.figure.savefig("Interest Rate")
Lending Club平台贷款利率中位数12.86%,利率最高值为31.00%,利率最小值为5.32%。利率是资金的价格,利率越高,借款人借贷成本越高,借款人违约的可能性越高。
多维变量分析
1.探索贷款与时间的关系
data_group_by_date = analysis_data.groupby(['issue_d']).sum()
data_group_by_date.reset_index(inplace=True)
data_group_by_date['issue_month'] = data_group_by_date['issue_d'].apply(lambda x: x.to_period('M')) # 新增月份列
loan_amount_group_by_month = data_group_by_date.groupby('issue_month')['loan_amnt'].sum() #按月份统计贷款金额
loan_amount_group_by_month_df = pd.DataFrame(loan_amount_group_by_month).reset_index() # 输出结果转成DataFrame
loan_amount_group_by_month_df
# 可视化
plt.figure(figsize=(15, 9))
sns.set()
sns.set_context("notebook", font_scale=1, rc={"lines.linewidth": 2})
plot1 = sns.barplot(y= 'loan_amnt', x='issue_month',data=loan_amount_group_by_month_df )
plt.xlabel('Month')
plt.ylabel('Loan_amount')
plt.title('Mounth VS Loan_amount')
plot1.figure.savefig("Mounth VS Loan_amount.png")
本数据集包含2017Q3, Q4, 2018Q1的数据,初步看来Leding Club平台在该时间段业务趋于平稳。
2.探索贷款金额与州之间的关系
data_group_by_state = analysis_data.groupby(['addr_state'])['loan_amnt'].sum() # 按州统计贷款金额
data_group_by_state_df= data_group_by_state.reset_index() # 将结果转为 dataframe
sns.set()
plt.figure(figsize=(15, 9))
sns.set_context("notebook", font_scale=1, rc={"lines.linewidth": 5})
sbarplot = sns.barplot(y='loan_amnt' , x='addr_state' , data=data_group_by_state_df )
plt.xlabel('State')
plt.ylabel('Loan_amount')
plt.xticks(rotation=90)
plt.title('State VS Loan_amount')
sbarplot.figure.savefig("State VS Loan_amount")
得知Lending Club 的总部在加州,因此加州的市场开拓也相对其他较好。其次是德克萨斯州和纽约州。
同时,从风险防范角度来看,应重点审核这几个城市贷款申请人的基本信息。
3.探索信用评级、贷款期限和利率的关系
data_group_by_grade_term = analysis_data.groupby(['grade', 'term'])['int_rate'].mean()
data_group_by_grade_term_df = pd.DataFrame(data_group_by_grade_term).reset_index()
data_group_by_grade_term_pivot = data_group_by_grade_term_df.pivot(index='grade', columns='term', values='int_rate')
data_group_by_grade_term_pivot # 输出数据透视表
used_data['grade'].value_counts() # 查看信用评级的分布
B 87715
C 85857
A 63066
D 39259
E 11049
F 2823
G 1967
Name: grade, dtype: int64
从表格可以看出,P2P平台的利率最高档为30%,而利率最低档为7%左右,总体利率水平也相对传统银行较高。 信用评级从A到G,A的的借款人信用评分最高,财务状况较好,违约发生的可能性较低,因此利率也相对较低。
贷款期限长意味着不确定性增加,风险也随之增加,期限较长的贷款在同信用等级下的借款利率也相对高。
4.探索贷款用途与利率的关系
plt.figure(figsize=(15, 9))
sns.set_context("notebook", font_scale=1.5, rc={"lines.linewidth": 2.5})
#loans['int_rate_num'] = loans['int_rate'].str.rstrip("%").astype("float")
sboxplot = sns.boxplot(y="purpose", x="int_rate", data=analysis_data)
sns.despine(top=True)
plt.xlabel('Interest_Rate')
plt.ylabel('Purpose')
plt.xticks(rotation=90)
plt.show()
sboxplot.figure.savefig("Purpose VS Rate")
贷款用途分别为renewable_enery、small_business以及Other的贷款利率较高。其中贷款用途为renewable_enery的贷款利率为最高。
第六步,总结
1.Lending Club 平台特点平台业务持续稳定发展:平台平稳发展,业务主要集中于加州、德克萨斯州和纽约州。
平台贷款金额以 小额贷款为主,贷款金额主要集中在10,000美元左右,小而散的贷款金额能够很好的分散资金风险。
平台贷款利率较高,贷款利率集中在12.86%,贷款利率相对传统金融机构较高。
平台二季度违约风险得到良好的控制,平台贷款发生违约的数量较少,贷款正常状态占比为94.12%。
2.个人建议完善客户画像和产品设计:信贷业务开展前,首先要明确信贷机构的目标客户群、目标客户的特征和画像信息是什么。例如Lending Club平台的small business业务,中小企业目标群体的特征描述应包括能够反映企业的资产负债和现金流相关的财务报表信息或表外债务信息等。完整的客户信息有利于风控人员和系统分析把控违约风险。
优化贷款模型:完善客户信息的同时,借助机器学习的技术持续优化贷款模型。
参考链接:Rho:注册会计师带你探索风险分析(EDA)zhuanlan.zhihu.com