这次做一个信用卡违约率的分析项目,具体的数据集可以在这里下载 数据集传送门
提出问题
- 总体的违约率情况怎样
- 什么样的人群容易违约
- 违约模型的准确率怎样
数据集解读
这是一个台湾银行2005年的信用卡数据,首先观察数据集,了解一下个字段含义:
字段 | 含义 |
---|---|
ID | 客户ID |
LIMIT_BAL | 可透支金额(新台币) |
SEX | 性别 (1为男,2为女) |
EDUCATION | 教育程度 (1研究生2大学3高中4其他5和6未知) |
MARRIAGE | 结婚(1已婚2未婚3其他) |
AGE | 年龄 |
PAY_0 | 9月还款情况(0按时付款1延迟1个月…9延迟9个月以上) |
PAY_2 | 8月还款情况 |
PAY_3 | 7月还款情况 |
PAY_4 | 6月还款情况 |
PAY_5 | 5月还款情况 |
PAY_6 | 4月还款情况 |
BILL_AMT1 | 9月账单金额(新台币) |
BILL_AMT2 | 8月账单金额 |
BILL_AMT3 | 7月账单金额 |
BILL_AMT4 | 6月账单金额 |
BILL_AMT5 | 5月账单金额 |
BILL_AMT6 | 4月账单金额 |
default.payment.next.month | 下一个月是否违约(1是0否) |
以上就是每一个字段的含义,可以看到性别以及教育程度有未知以及其他的出现,后面需注意一下。
数据探索
首先导入所需要的库以及文件
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split,GridSearchCV,learning_curve
from sklearn.pipeline import Pipeline
import warnings
warnings.filterwarnings('ignore')
接下来导入数据集观察一下整个数据集的情况
data = pd.read_csv(r'C:\Users\11060\Desktop\Card.csv')
data.describe()
图片太大就不放上来了,可以观察到数据集一共有30000条数据
data.rename(columns={'default.payment.next.month':'next_month'},inplace=True) # 特征名太长修改一下
plt.rcParams['font.sans-serif']=['SimHei']
data['next_month'].value_counts().plot(kind='bar')
plt.xlabel('违约 or 未违约')
plt.ylabel('数量')
可以看到违约的数量大概是未违约的1/4,也就是25%,数据的量级还可以,不需要数据集进行采样处理,当低于20%的时候就需要警醒,低于10%就得做处理
接下来看看各个特征下的违约情况
# 性别因素
sex_next_month = pd.crosstab(data['SEX'],data['next_month'])
sex_next_month.plot(kind='bar',stacked=True)
由堆叠图可以看到性别因素对违约率并没有显著影响,两种性别的违约率占各自总体比例相近。
# 教育程度
education_next_month = pd.crosstab(data['EDUCATION'],data['next_month']).plot(kind='bar',stacked = True)
由图可以看到信用卡客户大学学历以上用户占大多数,且学历对违约率也没有较大影响,
# 婚姻
education_next_month = pd.crosstab(data['MARRIAGE'],data['next_month']).plot(kind='bar',stacked = True)
可以看到婚姻对违约率也没有什么显著影响,在后面的建模部分可能可以将字段删除
数据处理
由上一步我们可以看到数据集中有一些其他数据,例如学历为0或者4、5、6的,婚姻为其他的,这些数据是缺失值,但是用其余数值填补了,数量小,对建模没有作用,可以考虑删除,客户ID一列无用,作删除处理
data.drop('ID',axis=1,inplace=True)
data1 = data[~data['MARRIAGE'].isin([0,3])]
data2 = data1[~data1['EDUCATION'].isin([0,4,5,6])]
print(data2.shape)
# output
(29163, 24)
其余的数值做标准化处理,但是可以放进Pipeline中一起执行所以代码放在建模分析部分
建模分析
首先划分训练集和测试集
y = np.array(data2.iloc[:,data2.columns == 'next_month'])
X = np.array(data2.iloc[:,data2.columns != 'next_month'])
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.33,stratify=y,random_state=1)
构造分类器
classifiers = [ # 模型选择
SVC(random_state=1),
KNeighborsClassifier(metric='minkowski')
]
classifires_name = [ # 模型名字,Pipeline需要
'svc',
'KNN'
]
classifire_param_grid = [ # 模型参数
{'svc__C':[0.1,1,10], 'svc__gamma':[0.1,0.2,0.3]}, # C参数和gamma参数是svm最重要的两个参数
# C是惩罚函数,值越高越不能容忍误差,但是容易过拟合
# gamma是当核函数为RBF时候自带的参数,值越大,支持向量越少,支持向量的个数会影响训练和预测速度
{'KNN__n_neighbors':[1,2,3,4,5,6,7,8,9,10]},
]
接下来构建模型拟合函数,调用模型预测
def searchgrid(pipeline,X_train,y_train,test_x,test_y,param_grid,score='accuracy'):
model = GridSearchCV(estimator=pipeline,param_grid=param_grid,scoring=score) # 寻找最优参数
gird = model.fit(X_train,y_train)
predict_y = model.predict(X_test)
print('GridSearchCV的最优参数为',gird.best_params_)
print('GridSearchCV的最优参数为',gird.best_score_)
print('准确率为',accuracy_score(y_test,predict_y))
for model,model_name,param_gird in zip(classifiers,classifires_name,classifire_param_grid):
pipeline = Pipeline([
('ss',StandardScaler()), # 标准化数据
(model_name,model)
])
searchgrid(pipeline,X_train,y_train,X_test,y_test,param_gird,score='accuracy') # 调用函数
# output
GridSearchCV的最优参数为 {'svc__C': 1, 'svc__gamma': 0.1}
GridSearchCV的最优参数为 0.8163672654690619
准确率为 0.8180590191188695
GridSearchCV的最优参数为 {'KNN__n_neighbors': 10}
GridSearchCV的最优参数为 0.8022416705051436
准确率为 0.8075644222776392
可以看到SVM的模型预测准确率为0.82,最佳参数惩罚系数为1,gamma为0.1
KNN最优参数n_neighbors(邻居数)为3
实际的运行中发现最优解的寻找过程时间较长,主要是因为自己参数设置较多,像KNN可以设置跨度大点的数值。
总结与不足
- 性别、年龄、学历对违约率没有较大的影响,即无显著相关性
- 使用SVM可以使违约率的分类正确率达到0.82
- 此次分析只用了两个模型,模型少