前言
本文章对小额贷款《Loan Data》的数据进行分析,用的是pycharm IDE,主要用到的python模块是pandas和pyecharts。pandas主要用于数据的导入、导出以及数据处理等,pyecharts主要用于数据可视化。
一、数据理解Loan Datawww.kaggle.com
数据包含有11个字段,500行数据。
数据字段译文如下:
loan_ID =======>贷款ID
loan_status=======>贷款状态
Principal=======>贷款金额
terms=======>贷款期限
effective_date=======>开始时间
due_date=======>到期时间
paid_off_time=======>还款时间
past_due_days=======>逾期天数
age=======>年龄
education=======>教育水平
gender=======>性别
二、数据清洗
数据清洗处理无非就是补选改构。
❥ 补一般是对缺失值的处理,缺失值我们会根据我们具体的分析方向去判断缺失值怎么去处理,列如:缺失值是用户的月收入,那么跟我们分析贷款行为有着很大的影响,那么我们就会想办法补全这些缺失值(咨询用户补全、众数补全、预测补全等);假如是一些跟我们分析方向影响不大的(业务能力的判断),我们直接补零就好了(尽量不要删除,不然会影响到其他字段的完整性)。
❥ 选(删)就很容易理解了,删就是删掉一些对我们分析方向毫无影响的字段(列),或者是一些缺失值比较多的条目(行);其实删和选,看个人习惯,不用删,我们就选择我们需要的字段或者条目就好了。
❥ 改,当我们遇到一些像性别这种字段的时候,我们通常会把其转换为阿拉伯数字,方便统计,所在在本篇文章我会把性别这一字段的'male':改成1, 'female'改成 0。
❥ 构的话就是源数据不能满足我们的分析需求,那么我们就会去自己构造数据,比如我们在数据源中会有年龄这个字段,但是我们要按一个年龄一个年龄的去统计就很麻烦,而且不直观,那么我们就好把年龄构成年龄段(青年、中年、老年)的形式,方便我们后面的分析。
1.缺失值
首先我们来看看哪些字段有缺失值。
看代码:
import pandas as pd # 导入模块
from pyecharts import *
data = pd.read_csv('..\data\\text\loan_data.csv') # 读入数据源
def data_colse(): #定义方法
print(data.isnull().sum()) # 查看缺失值
可以看到还款时间和逾期天数分别有100条和300条的缺失值;根据数据,我们可以看还款时间为缺失值的是逾期客户,就是到统计时间时,还没有还款的客户,在这里我们不用去管它;而逾期天数缺失值是正常还款的客户,在这里我们用零去补全缺失值,方便统计。。
data['past_due_days'].fillna(0, inplace=True)
2.修改数据显示形式
将'loan_status'还款状态的'PAIDOFF': 1, 'COLLECTION': 2, 'COLLECTION_PAIDOFF': 3
'education'受教育程度'High School or Below': 1, 'college': 2, 'Bechalor': 3, 'Master or Above': 4
'Gender'性别'male': 1, 'female': 0
然后再将字段名给改成中文,方便我们阅读。
loan_status_dict = {'PAIDOFF': 1, 'COLLECTION': 2, 'COLLECTION_PAIDOFF': 3}
data['还款状态'] = data['loan_status'].map(loan_status_dict)
data.drop('loan_status', inplace=True, axis=1) # 删除loan_status字段
# print(data.groupby('学历').agg('count')) # 统计各学历的人数
education_dict = {'High School or Below': 1, 'college': 2, 'Bechalor': 3, 'Master or Above': 4}
data['受教育程度'] = data['education'].map(education_dict)
data.drop('education', inplace=True, axis=1)
gender_dict = {'male': 1, 'female': 0}
data['性别'] = data['Gender'].map(gender_dict)
data.drop('Gender', inplace=True, axis=1)
col = {'Loan_ID': '贷款人ID', 'Principal': '贷款金额', 'terms': '期限','effective_date': '起始时间',
'due_date': '到期时间', 'paid_off_time': '偿还时间','past_due_days': '逾期天数', 'age': '年龄'
} # 定义列名list
data.rename(columns=col, inplace=True)
3.构造数据
将年龄以年龄段[青年(age<=30)、中年(31<=age<=46)、老年(age>46)]的形式分开,方面我们后面的分析。
返回处理完的DataFrame数据。
data['年龄段'] = data['年龄'].apply(lambda x: '青年' if x <= 30 else ('中年' if 31 <= x <= 46 else '老年'))
data_out = data.copy()
# data_out.to_csv('..\data\\text\loan_data_out.csv', index=False, encoding='utf-8_sig')
return data_out # 返回data_out
三、数据分析
1.逾期天数统计
对于客户的逾期,我们将其分类,分为C、1+、7+、15+、30+,其中C为正常还款的客户,而1+、7+、15+、30+分别为逾期1-6天、逾期7-14天、逾期15-30天;
分类要具体看公司模式,银行里面一般分M0(正常还款)、M1(逾期1-30天)、M2……
def past_due_days():
data_out = data_colse() # 接收方法返回值
zero = 0
one = 0
seven = 0
fifty = 0
thirty = 0
for _, i in data_out.iterrows():
if i['逾期天数'] == 0:
zero += 1
elif 1 <= i['逾期天数'] <= 7:
one += 1
elif 8 <= i['逾期天数'] <= 14:
seven += 1
elif 15 <= i['逾期天数'] <= 30:
fifty += 1
else:
thirty += 1
dict_day = {'C': zero, '1+': one, '7+': seven, '15+': fifty, '30+': thirty}
然后给数据来个可视化,看看逾期的人数分布;图会在当前目录下生成一个'逾期详情饼图.html‘文件,点开用浏览器打开就可以看到画的图了。
# 画出饼图
col_bar = list(dict_day.keys())
data_bar = list(dict_day.values())
pie = Pie('逾期详情', '标本数:%s' % (len(data_out)), title_pos="center")
pie.add('', col_bar, data_bar, is_label_show=True, is_legend_show=True, label_formatter='{d}%', legend_top='90%')
pie.render('逾期详情饼图.html')
从可视化图上,我们可以看到有60%的客户还是正常还款的,而有20.2%的客户逾期天数达到30+以上。
2.学历逾期
我们看看各个学历逾期的占比
def analyze():
data_out = data_colse()
# print(data_out['贷款金额'].describe())
# 学历逾期
total_overdue_education = len(data_out[data_out['逾期天数'] > 0])
below_peoples = data_out[data_out['受教育程度'] == 1][data_out[data_out['受教育程度'] == 1]['逾期天数'] > 0] # 学历高中逾期条目
college_peoples = data_out[data_out['受教育程度'] == 2][data_out[data_out['受教育程度'] == 2]['逾期天数'] > 0] # 学历大专逾期条目
bechalor_peoples = data_out[data_out['受教育程度'] == 3][data_out[data_out['受教育程度'] == 3]['逾期天数'] > 0] # 学历本科逾期条目
master_peoples = data_out[data_out['受教育程度'] == 4][data_out[data_out['受教育程度'] == 4]['逾期天数'] > 0] # 学历硕士逾期条目
education_dict = {'高中逾期占比': len(below_peoples) / total_overdue_education,
'大专逾期占比': len(college_peoples) / total_overdue_education,
'本科逾期占比': len(bechalor_peoples) / total_overdue_education,
'硕士逾期占比': len(master_peoples) / total_overdue_education
}
print('学历逾期:', education_dict)
# 学历逾期占比图
education_col = education_dict.keys()
education_data = education_dict.values()
education_pie = Pie('学历逾期图', '样本总数:%s' % total_overdue_education)
education_pie.add('', education_col, education_data, is_label_show=True, is_legend_show=True,
label_formatter='{b}:{d}%')
education_pie.render('学历逾期图.html')
从图上可看到,高中和大专学历逾期占了86.5%之多,而本科学历有13%的客户,而硕士学历只有0.5%的逾期客户,可以看到学历越高还款欲望会越高。
3.年龄段占比
我们看看各年龄段逾期的占比
# 年龄段逾期
total_age = len(data_out[data_out['逾期天数'] > 0])
youth = data_out[data_out['年龄段'] == '青年'][data_out[data_out['年龄段'] == '青年']['逾期天数'] > 0] # 青年逾期条目
midlife = data_out[data_out['年龄段'] == '中年'][data_out[data_out['年龄段'] == '中年']['逾期天数'] > 0] # 中年逾期条目
agedness = data_out[data_out['年龄段'] == '老年'][data_out[data_out['年龄段'] == '老年']['逾期天数'] > 0] # 老年逾期条目
age_dict = {'青年逾期占比': len(youth) / total_age,
'中年逾期占比': len(midlife) / total_age,
'老年逾期占比': len(agedness) / total_age
# 年龄段逾期
age_col = age_dict.keys()
age_data = age_dict.values()
age_pie = Pie('年龄段逾期图', '样本总数:%s' % total_age)
age_pie.add('', age_col, age_data, is_label_show=True, is_legend_show=True,
label_formatter='{b}:{d}%')
age_pie.render('年龄段逾期图.html')
从图上可看到青年逾期56%,中年逾期42%,而老年逾期占比只有2%,可以得出年龄段越高,还款欲望越高。
4.性别逾期
我们接下来看看性别逾期概率
two_state = data_out[data_out['还款状态'] == 2]
man_two = data_out[data_out['性别'] == 1][data_out[data_out['性别'] == 1]['还款状态'] == 2]
print(f'男性逾期比率:{len(man_two) / len(two_state) * 100}%')
print(f'女性逾期比率:{round((1 - (len(man_two) / len(two_state))) * 100, 2)}%')
性别逾期这个比例差别有点大,不好判断,有可能是样本的不平衡的问题。
四、总结
有60%的客户还是正常还款的,而有20.2%的客户逾期天数达到30+以上。
高中和大专学历逾期占了86.5%之多,而本科学历有13%的客户,而硕士学历只有0.5%的逾期客户,可以看到学历越高还款欲望会越高。
青年逾期56%,中年逾期42%,而老年逾期占比只有2%,可以得出年龄段越高,还款欲望越高。