项目8:信用违约预测-集成学习
目录
背景说明
项目介绍
导入模块
数据加载
分析与处理数据
划分数据集
使用随机森林创建并训练模型
通过参数搜索和过采样,缓解标签不平衡问题
小结
背景说明
风险已经成为了今年金融市场的重要主题之一,银行作为贷方,随时都面临着借贷者违约的风险。传统的专家规则在金融科技时代逐渐过时,机器学习和金融业务的交叉也延伸到信贷领域。违约预测就是其中一重要应用。本实验基于信贷业务场景中一个月内的抽样数据,数据集有34个维度,Target表示客户在接下来一个月是否有违约。模型生成后可使用当前月的数据预测接下来一个月客户是否会违约。
项目介绍
违约预测只有违约和没有预约两种结果,是个二分类问题。针对二分类问题,可使用的算法有逻辑回归、朴素贝叶斯、支持向量机、树模型等。本实验选用集成学习的算法来拟合数据。考虑到样本极度不均衡,模型评价选用综合指标f1_score。
导入模块
# 数据读取、处理、分析、可视化,算法模块等
import pandas as pd
import numpy as np
#导入相关包
%matplotlib inline
# import seaborn as sns
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
数据加载
读入数据,数据文件是dataset-credit-default.csv,定义为df。查看数据尺寸、打印信息,##查看Target的分布 ,是否违约(1是,0否)等
df = pd.read_csv('./数据集/dataset-credit-default.csv')
df
# 查看数据尺寸
print(df.shape)
# 打印信息
print(df.info())
# 查看Target的分布,是否违约(1是,0否)
print(df['Target'].value_counts(normalize=True))
分析与处理数据
观察数据缺失情况,把缺失比例超过20%的数据列删掉
data = df[df.columns[df.notnull().sum()/len(df)>0.8]].dropna(axis=0)
划分数据集
提取特征数据X和目标数据y。
X = data.drop('Target', axis=1)
y = data['Target']
划分训练集和测试集,通过观察发现正样本与负样本非常不平衡。将数据集作3:1的划分,按照标签比例做分层抽样,分出训练集和测试集,观察每个数据集中正负样本数量。
from sklearn.model_selection import train_test_split
# 3:1的划分,按照标签比例做分层抽样
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, stratify=y, random_state=42)
# 观察每个数据集中正负样本数量
print(y_train.value_counts())
print(y_test.value_counts())
引入StandardScaler标准化工具库,对训练集和测试集做标准化
from sklearn.preprocessing import StandardScaler
# 对训练集和测试集做标准化
std_scaler = StandardScaler().fit(X_train)
X_train_std = std_scaler.transform(X_train)
X_test_std = std_scaler.transform(X_test)
标准化后的测试集
X_train_std
X_test_std
查看X_train_std:
模块化处理:对从分析与处理数据-划分数据集进行函数数(模块化)处理
# 通过函数化的编程思想,把上面数据预处理的过程模块化
# 实现 分析与处理数据 -- 划分数据集 -- 对训练集和测试集做标准化
def process_data(df):
"""
传入读入的df
"""
# 把缺失比例超过20%的数据列删掉
data = df[df.columns[df.notnull().sum()/len(df)>0.8]].dropna(axis=0)
# 提取特征数据X和目标数据y
X = data.drop('Target', axis=1)
y = data['Target']
# 3:1的划分,按照标签比例做分层抽样
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25,
stratify=y, random_state=42)
# 此时得到了return的y_train, y_test,还需标准化X_train, X_test
# 对训练集和测试集做标准化
std_scaler = StandardScaler().fit(X_train)
X_train_std = std_scaler.transform(X_train)
X_test_std = std_scaler.transform(X_test)
# 返回标准化后的训练集、测试集和训练标签、测试标签
return X_train_std,X_test_std,y_train, y_test
测试模块化后的函数是否可用
df2 = pd.read_csv('./数据集/dataset-credit-default.csv')
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X_train_std,X_test_std,y_train, y_test = process_data(df2)
X_train_std,X_test_std,len(X_train_std),len(X_test_std)
使用随机森林创建并训练模型
引入随机森林的库,构建并训练模型。
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
# 创建随机森林分类器
rf_model = RandomForestClassifier(random_state=42)
# 训练模型
rf_model.fit(X_train_std, y_train)
对模型进行评价:准确率、召回率、精确率和f1分数。
# 对测试集进行预测
y_test_pred1 = rf_model.predict(X_test_std)
# 计算评估指标
accuracy = accuracy_score(y_test, y_test_pred1)
recall = recall_score(y_test, y_test_pred1)
precision = precision_score(y_test, y_test_pred1)
f1 = f1_score(y_test, y_test_pred1)
# 打印评估结果
print(f"准确率: {accuracy:.4f}")
print(f"召回率: {recall:.4f}")
print(f"精确率: {precision:.4f}")
print(f"F1分数: {f1:.4f}")
观察混淆矩阵,深入了解模型性能
from sklearn.metrics import ConfusionMatrixDisplay, confusion_matrix
cm = confusion_matrix(y_test, y_test_pred1, labels=rf_model.classes_)
disp_1 = ConfusionMatrixDisplay(confusion_matrix=cm,display_labels=rf_model.classes_)
disp_1.plot()
通过参数搜索和过采样,缓解标签不平衡问题
正反样本分开
X_train_0 = X_train[y_train==0]
y_train_0 = y_train[y_train==0]
X_train_1 = X_train[y_train==1]
y_train_1 = y_train[y_train==1]
对正样本过采样
# 过采样后的正样本数量将接近负样本数量的一半,从而一定程度上减少类别不平衡
from sklearn.utils import resample
X_train_1_res,y_train_1_res = resample(X_train_1,y_train_1,replace=True,n_samples=int(len(X_train_0)*0.5),random_state=42)
X_train_res = np.vstack([X_train_0,X_train_1_res])
y_train_res = np.hstack([y_train_0,y_train_1_res])
# 引入StandardScaler标准化工具库
from sklearn.preprocessing import StandardScaler
#对训练集和测试集做标准化
std_scaler_res = StandardScaler().fit(X_train_res)
X_train_std_res = std_scaler.transform(X_train_res)
from sklearn.model_selection import cross_val_score
cv_scores = cross_val_score(rf_model, X_train_std_res, y_train_res, cv=5)
print('cross validation score of model version1 {}'.format(cv_scores))
随机森林调参
参数搜索矩阵如下:
param_test0 = {'class_weight':[{0:0.8,1:0.2},{0:0.7,1:0.3},{0:0.1,1:0.9},'balanced'],
'max_depth':[2,4,6,8],
'n_estimators':[50,100,200]}
from sklearn.model_selection import GridSearchCV
# 创建 GridSearchCV 对象
grid_search = GridSearchCV(estimator=rf_model, param_grid=param_test0, scoring='f1', cv=5, n_jobs=-1, verbose=1)
# 执行网格搜索
grid_search.fit(X_train_std_res, y_train_res)
# 输出最佳参数
print("最佳参数:", grid_search.best_params_)
print("最佳分数:", grid_search.best_score_)
# 输出所有结果
results = grid_search.cv_results_
for mean_score, params in zip(results['mean_test_score'], results['params']):
print(f"参数: {params}, 平均分数: {mean_score:.4f}")
随机森林模型效果评估
# 使用最佳参数构建随机森林模型
rf_model_res = RandomForestClassifier(
class_weight='balanced',
max_depth=8,
n_estimators=200,
random_state=42
)
# 训练模型(使用过采样后的数据)
rf_model_res.fit(X_train_std_res, y_train_res)
# 对测试集进行预测
y_pred_res = rf_model_res.predict(X_test_std)
# 计算评估指标
accuracy_res = accuracy_score(y_test, y_pred_res)
recall_res = recall_score(y_test, y_pred_res)
precision_res = precision_score(y_test, y_pred_res)
f1_res = f1_score(y_test, y_pred_res)
# 打印评估结果
print("过采样后的模型性能:")
print(f"准确率: {accuracy_res:.4f}")
print(f"召回率: {recall_res:.4f}")
print(f"精确率: {precision_res:.4f}")
print(f"F1分数: {f1_res:.4f}")
观察混淆矩阵
# 计算混淆矩阵
conf_matrix_res = confusion_matrix(y_test, y_pred_res)
# 绘制混淆矩阵
plt.figure(figsize=(8, 6))
sns.heatmap(conf_matrix_res, annot=True, fmt='d', cmap='Blues',
xticklabels=['Predicted 0', 'Predicted 1'],
yticklabels=['Actual 0', 'Actual 1'])
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix (After Oversampling)')
plt.show()
过采样前后的结果对比
# 过采样前的模型性能(假设已经训练过并保存了结果)
print("过采样前的模型性能:")
print(f"准确率: {accuracy:.4f}")
print(f"召回率: {recall:.4f}")
print(f"精确率: {precision:.4f}")
print(f"F1分数: {f1:.4f}")
# 过采样后的模型性能
print("\n过采样后的模型性能:")
print(f"准确率: {accuracy_res:.4f}")
print(f"召回率: {recall_res:.4f}")
print(f"精确率: {precision_res:.4f}")
print(f"F1分数: {f1_res:.4f}")
过采样前后的混淆矩阵的结果对比
# 过采样前的混淆矩阵(假设已经计算过并保存为 conf_matrix)
plt.figure(figsize=(12, 5))
# 过采样前的混淆矩阵
plt.subplot(1, 2, 1)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['Predicted 0', 'Predicted 1'],
yticklabels=['Actual 0', 'Actual 1'])
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix (Before Oversampling)')
# 过采样后的混淆矩阵
plt.subplot(1, 2, 2)
sns.heatmap(conf_matrix_res, annot=True, fmt='d', cmap='Blues',
xticklabels=['Predicted 0', 'Predicted 1'],
yticklabels=['Actual 0', 'Actual 1'])
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix (After Oversampling)')
plt.tight_layout()
plt.show()
小结
本实验主要使用Python进行数据预处理、数据分析,使用Matplotlib做可视化分析,使用过采样方法平衡正反例数据,使用随机森林建模,使用网格搜索来寻找最优参数组合。违约预测问题面临着所需数据维度多、正负样本严重不均衡等问题,在实际应用上,可以多搜集各类维度的特征,多尝试过采样、欠采样,也可以尝试使用无监督学习、深度神经网络等。