【竞赛系列】机器学习实操项目04——客户信用评估模型开发全流程(baseline)
上一章:机器学习实操项目03——Scikit-learn介绍及简单分类案例
下一章:
机器学习核心知识点目录:机器学习核心知识点目录
机器学习实战项目目录:【从 0 到 1 落地】机器学习实操项目目录:覆盖入门到进阶,大学生就业 / 竞赛必备
文章目录
- 客户信用评估模型开发全流程
- 任务总览
- 1. 数据加载与预处理
- 2. 划分训练集和验证集
- 3. 特征预处理
- 4. 模型训练与评估
- 5. 最佳模型选择与评估
- 6. 混淆矩阵分析
- 7. 业务解读
- 8. 测试集预测与提交
- 总结
- 完整代码及中间结果
客户信用评估模型开发全流程
任务总览
本项目旨在开发一个客户信用评估模型,通过分析客户的基本信息、账户特征等数据,预测客户是否为"好客户"(Target=1)或"坏客户"(Target=0)。这一模型可帮助金融机构在信贷审批过程中做出更合理的决策,平衡风险控制与业务发展。
整个流程包括:数据加载与预处理、数据集划分、特征工程、模型训练与评估、模型选择与解读、以及最终预测等关键步骤。
通过网盘分享的文件:用户信用评分数据集
链接: https://pan.baidu.com/s/1F2R0rOLuw4_ntaKMPL8otg?pwd=1x27 提取码: 1x27
1. 数据加载与预处理
功能说明
这一步骤的主要目的是加载原始数据并进行初步处理,为后续建模做准备。包括处理缺失值、分离特征与目标变量等。
# 读取训练数据和测试数据
train = pd.read_csv('train.csv') # 加载训练数据集(包含目标变量)
test = pd.read_csv('test.csv') # 加载测试数据集(不包含目标变量,用于最终预测)
pd.read_csv():pandas库的函数,用于从CSV文件中读取数据并转换为DataFrame格式,方便后续的数据处理和分析。
# 处理缺失值 - 只对分类特征进行简单填充
# 将Credit_Product列的缺失值填充为'Unknown'
train['Credit_Product'] = train['Credit_Product'].fillna('Unknown')
test['Credit_Product'] = test['Credit_Product'].fillna('Unknown')
fillna():pandas的DataFrame方法,用于填充缺失值。这里将缺失的信用产品信息标记为’Unknown’,而不是简单删除,以保留更多数据信息。
# 分离特征和目标变量
X = train.drop(['ID', 'Target'], axis=1) # 特征数据:删除ID(无预测价值)和Target(目标变量)
y = train['Target'] # 目标变量:客户是否为好客户(1表示好客户,0表示坏客户)
drop():pandas的DataFrame方法,用于删除指定列(axis=1表示删除列)。这里移除ID列(仅作为标识)和Target列(需要预测的目标)。
2. 划分训练集和验证集
功能说明
将训练数据进一步划分为训练集(用于模型训练)和验证集(用于模型评估),避免模型过拟合并客观评估模型性能。
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, # 验证集比例20%stratify=y, # 按目标变量分层抽样random_state=42 # 设置随机种子确保结果可复现
)
train_test_split():sklearn库的函数,用于将数据集随机划分为训练集和验证集。
- test_size=0.2:指定验证集占总数据的20%
- stratify=y:按目标变量y的分布进行分层抽样,确保训练集和验证集中目标变量的比例一致
- random_state=42:设置随机种子,保证每次运行代码得到相同的划分结果,便于结果复现
3. 特征预处理
功能说明
对不同类型的特征进行预处理,使特征满足模型输入要求,同时提升模型性能。主要包括对分类特征进行独热编码,对数值特征进行标准化。
# 定义分类特征和数值特征
cat_cols = ['Gender', 'Region_Code', 'Occupation', 'Channel_Code', 'Credit_Product', 'Is_Active']
num_cols = ['Age', 'Vintage', 'Avg_Account_Balance']
特征分为两类:
- 分类特征(cat_cols):非数值型特征,如性别、职业等
- 数值特征(num_cols):可直接进行数值计算的特征,如年龄、账户余额等
# 对分类变量进行独热编码
encoder = OneHotEncoder(handle_unknown='ignore') # 创建独热编码器
X_train_encoded = encoder.fit_transform(X_train[cat_cols]) # 拟合并转换训练集
X_val_encoded = encoder.transform(X_val[cat_cols]) # 转换验证集
X_test_encoded = encoder.transform(test[cat_cols]) # 转换测试集
OneHotEncoder():sklearn的预处理类,用于将分类特征转换为独热编码形式。
- handle_unknown=‘ignore’:遇到训练集中未出现的类别时忽略,避免错误
- fit_transform():先根据训练数据拟合编码器(学习类别信息),再进行转换
- transform():使用已拟合的编码器对新数据(验证集/测试集)进行转换,保证编码方式一致
# 数值特征标准化(Z-score标准化)
scaler = StandardScaler() # 创建标准化器
X_train_num = scaler.fit_transform(X_train[num_cols]) # 拟合并转换训练集
X_val_num = scaler.transform(X_val[num_cols]) # 转换验证集
X_test_num = scaler.transform(test[num_cols]) # 转换测试集
StandardScaler():sklearn的预处理类,用于对数值特征进行标准化(Z-score转换),使特征均值为0,标准差为1。
- 标准化可以消除不同特征间的量纲影响,使模型更易收敛
# 合并处理后的特征
X_train_final = np.hstack([X_train_num, X_train_encoded.toarray()])
X_val_final = np.hstack([X_val_num, X_val_encoded.toarray()])
X_test_final = np.hstack([X_test_num, X_test_encoded.toarray()])
np.hstack():numpy库的函数,用于水平堆叠数组。这里将处理后的数值特征和编码后的分类特征合并,形成最终的特征矩阵。
4. 模型训练与评估
功能说明
训练多种分类模型,并使用验证集评估模型性能,选择最优模型。采用AUC(ROC曲线下面积)作为主要评估指标,适用于二分类问题且对不平衡数据较为稳健。
# 定义要比较的模型
models = [("Logistic Regression", LogisticRegression(max_iter=1000, random_state=42)),("Decision Tree", DecisionTreeClassifier(max_depth=5, random_state=42)),("Random Forest", RandomForestClassifier(n_estimators=100, random_state=42)),("KNN", KNeighborsClassifier(n_neighbors=30)),("Naive Bayes", GaussianNB())
]
选择了5种常见的分类算法进行比较:
- 逻辑回归:线性模型,可解释性强
- 决策树:非线性模型,可捕捉特征间的交互关系
- 随机森林:集成模型,通常性能更优
- K近邻:基于实例的学习,简单直观
- 朴素贝叶斯:基于概率的简单模型
# 评估每个模型
for name, model in models:model.fit(X_train_final, y_train) # 训练模型# 获取预测概率if hasattr(model, "predict_proba"):val_proba = model.predict_proba(X_val_final)[:, 1] # 预测为1的概率else:val_proba = model.decision_function(X_val_final)val_proba = (val_proba - val_proba.min()) / (val_proba.max() - val_proba.min()) # 归一化val_auc = roc_auc_score(y_val, val_proba) # 计算AUCprint(f"{name}: AUC = {val_auc:.4f}")
model.fit():模型训练方法,根据输入的特征矩阵和目标变量学习模型参数。
predict_proba():多数分类模型提供的方法,返回每个样本属于各个类别的概率。[:, 1]表示取样本属于类别1(好客户)的概率。
roc_auc_score():计算ROC曲线下面积(AUC)的函数。AUC取值范围为0-1,越接近1表示模型区分正负样本的能力越强。
5. 最佳模型选择与评估
功能说明
基于验证集的AUC值选择性能最优的模型,并进行更详细的评估,包括分类报告和混淆矩阵分析。
# 选择最佳模型
best_model_name, best_auc, best_model = max(results, key=lambda x: x[1])
通过比较各模型的AUC值,选择性能最优的模型(此处为决策树,AUC=0.8595)。
# 详细评估最佳模型
val_pred = best_model.predict(X_val_final) # 预测类别
print(classification_report(y_val, val_pred)) # 生成分类报告
predict():模型预测方法,返回样本的预测类别(0或1)。
classification_report():生成包含精确率(precision)、召回率(recall)、F1分数等指标的分类报告:
- 精确率:预测为正的样本中实际为正的比例
- 召回率:实际为正的样本中被正确预测的比例
- F1分数:精确率和召回率的调和平均
6. 混淆矩阵分析
功能说明
通过混淆矩阵更直观地分析模型的预测结果,了解模型在不同类别上的表现。
cm = confusion_matrix(y_val, val_pred)
tn, fp, fn, tp = cm.ravel()
confusion_matrix():计算混淆矩阵的函数,矩阵元素含义:
- TP(True Positive):真正例,实际为好客户且被正确预测
- FP(False Positive):假正例,实际为坏客户但被错误预测为好客户
- FN(False Negative):假反例,实际为好客户但被错误预测为坏客户
- TN(True Negative):真反例,实际为坏客户且被正确预测
7. 业务解读
功能说明
将模型的技术指标转化为业务指标,从业务角度解读模型表现,评估模型对实际业务的影响。
accuracy = (tp + tn) / (tp + tn + fp + fn) # 总体准确率
good_recall = tp / (tp + fn) # 好客户识别率(召回率)
bad_recall = tn / (tn + fp) # 坏客户识别率
从业务角度看:
- 假阳性(FP):将坏客户误判为好客户,可能导致坏账损失
- 假阴性(FN):将好客户误判为坏客户,会损失潜在收益
- 模型需要在两者之间找到平衡,根据业务策略调整阈值
8. 测试集预测与提交
功能说明
使用最佳模型对测试集进行预测,生成符合要求的提交文件,用于模型部署或竞赛提交。
# 测试集预测
test_proba = best_model.predict_proba(X_test_final)[:, 1]# 生成提交文件
submission = pd.DataFrame({'ID': test['ID'],'Target': test_proba
})
submission.to_csv('submission.csv', index=False)
生成包含客户ID和对应好客户概率的提交文件,概率值可用于业务决策(如设定阈值来确定是否批准信贷)。
总结
本项目通过完整的机器学习流程,从数据预处理到模型评估,最终构建了一个客户信用评估模型。决策树模型在本数据集上表现最佳,AUC达到0.8595,能够较好地区分好客户和坏客户。模型的业务解读帮助将技术结果转化为实际业务价值,为信贷决策提供数据支持。
完整代码及中间结果
# 导入必要的数据处理和机器学习库
import pandas as pd # 用于数据处理和分析
import numpy as np # 用于数值计算
import matplotlib.pyplot as plt # 用于数据可视化
from sklearn.model_selection import train_test_split # 用于划分训练集和验证集
from sklearn.preprocessing import StandardScaler, OneHotEncoder # 用于特征预处理
from sklearn.metrics import roc_auc_score, confusion_matrix, classification_report # 用于模型评估
# 1. 数据加载与预处理
# 读取训练数据和测试数据
train = pd.read_csv('train.csv') # 加载训练数据集
test = pd.read_csv('test.csv') # 加载测试数据集# 处理缺失值 - 只对分类特征进行简单填充
# 将Credit_Product列的缺失值填充为'Unknown'
train['Credit_Product'] = train['Credit_Product'].fillna('Unknown')
test['Credit_Product'] = test['Credit_Product'].fillna('Unknown')# 分离特征和目标变量
# 训练数据中删除ID列和Target列作为特征
X = train.drop(['ID', 'Target'], axis=1)
# 提取目标变量(客户是否为好客户)
y = train['Target']
# 2. 划分训练集和验证集
# 将数据分为训练集和验证集,验证集占20%
# 使用分层抽样确保训练集和验证集的目标变量分布一致
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, # 验证集比例20%stratify=y, # 按目标变量分层抽样random_state=42 # 设置随机种子确保结果可复现
)
print(X)
输出结果:
Gender | Age | Region_Code | Occupation | Channel_Code | Vintage | Credit_Product | Avg_Account_Balance | Is_Active | |
---|---|---|---|---|---|---|---|---|---|
0 | Male | 58 | RG264 | Self_Employed | X2 | 19 | No | 552449 | Yes |
1 | Female | 45 | RG271 | Self_Employed | X3 | 104 | Yes | 525206 | No |
2 | Female | 30 | RG278 | Other | X1 | 25 | No | 724718 | No |
3 | Female | 52 | RG283 | Self_Employed | X1 | 43 | Yes | 1452453 | No |
4 | Female | 76 | RG254 | Other | X1 | 57 | No | 1895762 | No |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
195720 | Female | 39 | RG279 | Self_Employed | X2 | 19 | Unknown | 1595992 | No |
195721 | Female | 46 | RG283 | Self_Employed | X2 | 27 | Yes | 1220029 | No |
195722 | Male | 68 | RG268 | Other | X3 | 104 | Yes | 1789781 | No |
195723 | Male | 30 | RG277 | Self_Employed | X2 | 15 | No | 722822 | Yes |
195724 | Female | 60 | RG268 | Self_Employed | X3 | 98 | Yes | 1837992 | Yes |
195725 rows × 9 columns
# 3. 特征预处理
# 定义分类特征和数值特征
# 分类特征列表
cat_cols = ['Gender', 'Region_Code', 'Occupation', 'Channel_Code', 'Credit_Product', 'Is_Active']
# 数值特征列表
num_cols = ['Age', 'Vintage', 'Avg_Account_Balance']# 对分类变量进行独热编码
# 创建独热编码器,忽略未知类别
encoder = OneHotEncoder(handle_unknown='ignore')
# 在训练集上拟合并转换分类特征
X_train_encoded = encoder.fit_transform(X_train[cat_cols])
# 在验证集上转换分类特征(使用训练集拟合的编码器)
X_val_encoded = encoder.transform(X_val[cat_cols])
# 在测试集上转换分类特征
X_test_encoded = encoder.transform(test[cat_cols])# 数值特征标准化(Z-score标准化)
# 创建标准化器
scaler = StandardScaler()
# 在训练集上拟合并转换数值特征
X_train_num = scaler.fit_transform(X_train[num_cols])
# 在验证集上转换数值特征(使用训练集拟合的标准化器)
X_val_num = scaler.transform(X_val[num_cols])
# 在测试集上转换数值特征
X_test_num = scaler.transform(test[num_cols])# 合并处理后的特征
# 水平堆叠数值特征和编码后的分类特征
X_train_final = np.hstack([X_train_num, X_train_encoded.toarray()])
X_val_final = np.hstack([X_val_num, X_val_encoded.toarray()])
X_test_final = np.hstack([X_test_num, X_test_encoded.toarray()])
# 打印形状检查
print(f"训练集形状: {X_train_final.shape}")
print(f"验证集形状: {X_val_final.shape}")
print(f"测试集形状: {X_test_final.shape}")
输出结果:
训练集形状: (156580, 53)
验证集形状: (39145, 53)
测试集形状: (50000, 53)
# 4. 模型训练与评估
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB# 定义要比较的模型
models = [("Logistic Regression", LogisticRegression(max_iter=1000, random_state=42)),("Decision Tree", DecisionTreeClassifier(max_depth=5, random_state=42)),("Random Forest", RandomForestClassifier(n_estimators=100, random_state=42)),("KNN", KNeighborsClassifier(n_neighbors=30)),("Naive Bayes", GaussianNB())
]# 评估每个模型
results = []
for name, model in models:# 训练模型model.fit(X_train_final, y_train)# 在验证集上预测概率# 对于不支持predict_proba的模型,使用decision_functionif hasattr(model, "predict_proba"):val_proba = model.predict_proba(X_val_final)[:, 1]else:# 对于SVM等模型,使用decision_functionval_proba = model.decision_function(X_val_final)# 将决策函数值缩放到0-1范围val_proba = (val_proba - val_proba.min()) / (val_proba.max() - val_proba.min())# 计算AUCval_auc = roc_auc_score(y_val, val_proba)# 保存结果results.append((name, val_auc, model))print(f"{name}: AUC = {val_auc:.4f}")
输出结果:
Logistic Regression: AUC = 0.8540
Decision Tree: AUC = 0.8595
Random Forest: AUC = 0.8477
KNN: AUC = 0.8509
Naive Bayes: AUC = 0.7988
# 5. 选择最佳模型
best_model_name, best_auc, best_model = max(results, key=lambda x: x[1])
print(f"\n最佳模型: {best_model_name}, AUC: {best_auc:.4f}")# 在验证集上详细评估最佳模型
val_pred = best_model.predict(X_val_final)# 对于支持概率预测的模型,获取概率
if hasattr(best_model, "predict_proba"):val_proba = best_model.predict_proba(X_val_final)[:, 1]
else:val_proba = best_model.decision_function(X_val_final)val_proba = (val_proba - val_proba.min()) / (val_proba.max() - val_proba.min())print("\n分类报告:")
print(classification_report(y_val, val_pred))
输出结果:
最佳模型: Decision Tree, AUC: 0.8595分类报告:precision recall f1-score support0 0.85 0.98 0.91 298401 0.85 0.47 0.60 9305accuracy 0.85 39145macro avg 0.85 0.72 0.76 39145
weighted avg 0.85 0.85 0.84 39145
# 6. 混淆矩阵分析
cm = confusion_matrix(y_val, val_pred)
tn, fp, fn, tp = cm.ravel()print("\n混淆矩阵:")
print(f"真正例(TP): {tp} - 实际好客户被正确识别为好客户")
print(f"假正例(FP): {fp} - 实际坏客户被错误识别为好客户")
print(f"假反例(FN): {fn} - 实际好客户被错误识别为坏客户")
print(f"真反例(TN): {tn} - 实际坏客户被正确识别为坏客户")
输出结果:
混淆矩阵:
真正例(TP): 4328 - 实际好客户被正确识别为好客户
假正例(FP): 737 - 实际坏客户被错误识别为好客户
假反例(FN): 4977 - 实际好客户被错误识别为坏客户
真反例(TN): 29103 - 实际坏客户被正确识别为坏客户
confusion_matrix(y_val, val_pred)
输出结果:
array([[29103, 737],[ 4977, 4328]], dtype=int64)
# 7. 业务解读
accuracy = (tp + tn) / (tp + tn + fp + fn)
good_recall = tp / (tp + fn)
bad_recall = tn / (tn + fp)print("\n业务解读:")
print(f"- 假阳性(FP): {fp} 个实际坏客户被错误分类为好客户,可能导致坏账损失")
print(f"- 假阴性(FN): {fn} 个实际好客户被错误分类为坏客户,损失潜在收益")
print(f"- 模型准确率: {accuracy:.2%}")
print(f"- 好客户识别率: {good_recall:.2%} (正确识别好客户的能力)")
print(f"- 坏客户识别率: {bad_recall:.2%} (正确识别坏客户的能力)")
输出结果:
业务解读:
- 假阳性(FP): 737 个实际坏客户被错误分类为好客户,可能导致坏账损失
- 假阴性(FN): 4977 个实际好客户被错误分类为坏客户,损失潜在收益
- 模型准确率: 85.40%
- 好客户识别率: 46.51% (正确识别好客户的能力)
- 坏客户识别率: 97.53% (正确识别坏客户的能力)
# 8. 测试集预测与提交
# 在测试集上预测
if hasattr(best_model, "predict_proba"):test_proba = best_model.predict_proba(X_test_final)[:, 1]
else:test_proba = best_model.decision_function(X_test_final)test_proba = (test_proba - test_proba.min()) / (test_proba.max() - test_proba.min())# 生成提交文件
submission = pd.DataFrame({'ID': test['ID'],'Target': test_proba
})
# submission.to_csv('submission.csv', index=False)
print("\n提交文件已生成: submission.csv")
输出结果:
提交文件已生成: submission.csv
上一章:机器学习实操项目03——Scikit-learn介绍及简单分类案例
下一章:
机器学习核心知识点目录:机器学习核心知识点目录
机器学习实战项目目录:【从 0 到 1 落地】机器学习实操项目目录:覆盖入门到进阶,大学生就业 / 竞赛必备