当前位置: 首页 > news >正文

逻辑回归 银行贷款资格判断案列优化 交叉验证,调整阈值,下采样与过采样方法

目录

一.交叉验证

1.参数选择与验证集的引入

2.交叉验证方法

3.交叉验证实现

 二.阈值的调整

1.什么是阈值

2.为什么要调整阈值

①业务目标的权衡:精确率与召回率的博弈

②样本不平衡问题

3.如何优化阈值

三.数据不均衡的处理方法

①下采样

1.下采样方法讲解

2.下采样优化后的完整银行贷款资格案例代码

3.下采样的实验结果

②过采样

1.过采样方法讲解

2.模型训练与优化

3.过采样优化后的完整银行贷款资格案例代码

4.过采样的实验结果


一.交叉验证

1.参数选择与验证集的引入

  • 直接使用测试集选择参数C会导致数据泄露(测试集间接参与训练),不科学。
  • 解决方案:从训练集中再划分验证集(如5万条),用于参数调优,测试集仅用于最终评估。
  • 验证集与测试集区别:验证集用于参数选择,测试集用于最终模型性能验证。
  • 测试集绝对不可参与训练或参数选择,仅用于最终模型评估。

2.交叉验证方法

  • 为充分利用数据,采用K折交叉验证(如10折):
    • 将训练集均分为K份(如10份),轮流用其中1份作为验证集,其余K-1份训练模型。
    • 计算K次验证结果的平均值作为参数选择的依据。
  • 优势:避免数据浪费,更科学评估参数效果。

3.交叉验证实现

  • 使用cross_val_score函数(需要导入),传入模型、训练数据、K值(如cv=8)及评估指标(如召回率scoring='recall')。
  • 逻辑回归参数:C(惩罚因子)、正则化方法(L1/L2)、优化算法(如LBFGS)、最大迭代次数(如max_iter=1000)。
  • 对每个C值进行交叉验证,记录平均召回率(如C=1时召回率0.617)。
  • 交叉验证结果需取平均值,对比不同参数性能后选择最优解。
  • 通过np.argmax选择最优参数(最终确定C=1为最佳惩罚因子)。如银行贷款案例的最佳C值选择如下
    # 交叉验证
    scores=[]
    c_param_range=[0.01,0.1,1,10,100]
    for i in c_param_range:lr = LogisticRegression(C=i,penalty='l2',solver='lbfgs',max_iter=1000)score = cross_val_score(lr,train_x,train_y,cv=8,scoring='recall')score_mean=sum(score)/len(score)scores.append(score_mean)print(score_mean)
    best_c=c_param_range[np.argmax(scores)]
    print('best_c=',best_c)

 二.阈值的调整

在逻辑回归中,阈值(Threshold)是预测阶段用于将模型输出的概率([0,1] 区间)转化为分类结果(正例 / 负例)的临界值。默认情况下,阈值通常设为 0.5(即概率≥0.5 判为正例,<0.5 判为负例),但在实际应用中,阈值需要根据业务目标和数据特性进行优化调整

1.什么是阈值

逻辑回归的核心是通过 sigmoid 函数将线性输出((z = w^Tx + b))转化为样本属于正例的概率: (P(y=1|x) = 1/(1 + e^{-z}})其中,(P(y=1|x)) 表示样本x属于正例的概率。阈值是一个人为设定的临界值(记为t),用于决策:

  • 若(P(y=1|x) >= t),则预测为正例((y=1));
  • 若(P(y=1|x) < t),则预测为负例((y=0))。

2.为什么要调整阈值

默认阈值 0.5 的合理性建立在 “正例和负例误判代价相同” 的假设上,但实际业务中,正例和负例的误判代价往往不同,因此需要调整阈值以优化模型的实际效果。具体原因包括:

①业务目标的权衡:精确率与召回率的博弈

模型的分类效果可通过混淆矩阵及衍生指标(精确率、召回率、F1 分数等)评估,而阈值直接影响这些指标:

  • 精确率(Precision):预测为正例的样本中,实际为正例的比例((P = TP/(TP + FP))),关注 “预测正例的准确性”;
  • 召回率(Recall):实际为正例的样本中,被正确预测为正例的比例((R = TP/(TP + FN))),关注 “是否漏检正例”;
  • 假阳性率(FPR):实际为负例的样本中,被误判为正例的比例((FPR = FP/(FP + TN)));
  • 假阴性率(FNR):实际为正例的样本中,被误判为负例的比例(FNR = FN/(TP + FN))。

阈值调整对指标的影响规律:

  • 提高阈值(t增大):模型更 “严格” 地判断正例,会减少假阳性(FP↓),但可能增加假阴性(FN↑),导致精确率升高、召回率降低;
  • 降低阈值(t减小):模型更 “宽松” 地判断正例,会减少假阴性(FN↓),但可能增加假阳性(FP↑),导致召回率升高、精确率降低。

例如:

  • 癌症筛查中,漏检(FN)的代价远高于误判(FP),因此需降低阈值以提高召回率(尽量不漏掉患者);
  • 垃圾邮件识别中,误判正常邮件为垃圾邮件(FP)的代价更高,因此需提高阈值以保证精确率(减少对正常邮件的干扰)。

②样本不平衡问题

当数据集中正负样本比例失衡(如正样本仅占 5%),默认阈值 0.5 可能导致模型 “偏向” 多数类(负例),正例识别率极低。此时需通过调整阈值平衡正负例的识别效果。

3.如何优化阈值

阈值优化的核心是根据业务目标选择合适的评估指标,通过遍历可能的阈值并计算指标表现,找到最优值,例如银行贷款案例的阈值更改如下:

thresholds=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
recalls=[]
for i in thresholds:y_predicted_proba=lr.predict_proba(test_x)y_predicted_proba=pd.DataFrame(y_predicted_proba)y_predicted_proba=y_predicted_proba.drop([0],axis=1)y_predicted_proba[y_predicted_proba[[1]] > i] = 1y_predicted_proba[y_predicted_proba[[1]] <= i] = 0recall=metrics.recall_score(test_y,y_predicted_proba)recalls.append(recall)print("{} Recall metric in the testing dataset:{:.3f}".format(i,recall))
best_t = thresholds[np.argmax(recalls)]
best_calls = max(recalls)
print("最佳阈值为:{} 对应的recalls为:{:.3f}".format(best_t,best_calls))

阈值选择逻辑

  • 若业务要求 “高精确率”(如推荐系统,避免推荐无关内容),选择 PR 曲线上精确率较高的点对应的阈值;
  • 若业务要求 “高召回率”(如欺诈检测,尽量捕捉所有欺诈),选择 PR 曲线上召回率较高的点对应的阈值;
  • 若需平衡两者,选择 F1 分数((F1 = 2×(P ×R)/(P + R)))最大的点对应的阈值。

三.数据不均衡的处理方法

例如银行贷款案例中训练集中类别为0的样本约28万条,类别为1的样本仅492条,导致模型性能受限。有两种解决方法:下采样和过采样方法

①下采样

1.下采样方法讲解

  • 下采样通过减少数据量(如从28万条中抽取720条)实现类别均衡,但可能遗漏部分未训练的特殊数据。

我们从类别为0的样本中随机抽取与类别为1等量的样本(391条),组合成均衡数据集(共782条),代码如下

# 下采样操作
positive_eg=train_data[train_data['Class']==0]
negative_eg=train_data[train_data['Class']==1]positive_eg=positive_eg.sample(len(negative_eg))
# 拼接数据
data_c=pd.concat([positive_eg,negative_eg])
train_x=data_c.iloc[:,:-1]
train_y=data_c.iloc[:,-1]

2.下采样优化后的完整银行贷款资格案例代码

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn import metricsdata = pd.read_csv('creditcard.csv')
scaler=StandardScaler()
data['Amount']=scaler.fit_transform(data[['Amount']])
data = data.drop(['Time'],axis=1)X=data.iloc[:,:-1]
y=data.iloc[:,-1]
train_x,test_x,train_y,test_y=train_test_split(X,y,test_size=0.3,random_state=400)train_x['Class'] = train_y
train_data=train_x
# 下采样操作
positive_eg=train_data[train_data['Class']==0]
negative_eg=train_data[train_data['Class']==1]positive_eg=positive_eg.sample(len(negative_eg))
# 拼接数据
data_c=pd.concat([positive_eg,negative_eg])
train_x=data_c.iloc[:,:-1]
train_y=data_c.iloc[:,-1]# 交叉验证
scores=[]
c_param_range=[0.01,0.1,1,10,100]
for i in c_param_range:lr = LogisticRegression(C=i,penalty='l2',solver='lbfgs',max_iter=1000)score = cross_val_score(lr,train_x,train_y,cv=5,scoring='recall')score_mean=sum(score)/len(score)scores.append(score_mean)print(score_mean)
best_c=c_param_range[np.argmax(scores)]
print('best_c=',best_c)lr=LogisticRegression(C=best_c)
lr.fit(train_x,train_y)
predicted=lr.predict(test_x)
print(metrics.classification_report(test_y,predicted))
# 更改阈值
thresholds=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
recalls=[]
for i in thresholds:y_predicted_proba=lr.predict_proba(test_x)y_predicted_proba=pd.DataFrame(y_predicted_proba)y_predicted_proba=y_predicted_proba.drop([0],axis=1)y_predicted_proba[y_predicted_proba[[1]] > i] = 1y_predicted_proba[y_predicted_proba[[1]] <= i] = 0recall=metrics.recall_score(test_y,y_predicted_proba)recalls.append(recall)print("{} Recall metric in the testing dataset:{:.3f}".format(i,recall))
best_t = thresholds[np.argmax(recalls)]
best_calls = max(recalls)
print("最佳阈值为:{} 对应的recalls为:{:.3f}".format(best_t,best_calls))0.8657142857142859
0.9085714285714286
0.9142857142857143
0.9142857142857143
0.9114285714285714
best_c= 1precision    recall  f1-score   support0       1.00      0.98      0.99     853011       0.06      0.89      0.11       142accuracy                           0.98     85443macro avg       0.53      0.94      0.55     85443
weighted avg       1.00      0.98      0.99     85443
0.1 Recall metric in the testing dataset:0.965
0.2 Recall metric in the testing dataset:0.923
0.3 Recall metric in the testing dataset:0.901
0.4 Recall metric in the testing dataset:0.901
0.5 Recall metric in the testing dataset:0.894
0.6 Recall metric in the testing dataset:0.894
0.7 Recall metric in the testing dataset:0.873
0.8 Recall metric in the testing dataset:0.866
0.9 Recall metric in the testing dataset:0.845
最佳阈值为:0.1 对应的recalls为:0.965

3.下采样的实验结果

  • 使用均衡化数据集训练后,模型召回率显著提升至89%
  • 调整阈值后召回率达到98.8%
  • 测试集表现稳定),未出现过拟合,说明下采样有效提取了代表性特征。
  • 副作用:精确率下降至0.06(预测为1的样本中仅6%正确),但业务更关注召回率(真实为1的样本中89%被找出)。
  • 下采样通过减少数据量(如从28万条中抽取720条)实现类别均衡,但可能遗漏部分未训练的特殊数据。

②过采样

1.过采样方法讲解

  • 过采样通过人工合成少数类数据(如从391条增至19.9万条)实现数据均衡。
  • 核心算法为SMOTE(合成少数类过采样技术),基于K近邻原理在少数类数据点间生成新样本。
  • 需安装imblearn库调用SMOTE函数,算法自动识别少数类并拟合。
  • 示例中拟合后数据量达45万条,需注意生成数据可能存在噪声。
    # 过采样操作
    from imblearn.over_sampling import SMOTE
    oversample=SMOTE(random_state=0)#保证数据拟合效果,随机种子
    os_x_train,os_y_train=oversample.fit_resample(train_x,train_y)train_x,test_x,train_y,test_y=train_test_split(os_x_train,os_y_train,test_size=0.3,random_state=400)
    

2.模型训练与优化

  • 过采样后数据需再次切分为训练集和测试集,以验证模型效果
  • 可以通过调整分类阈值进一步提升正确率

3.过采样优化后的完整银行贷款资格案例代码

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn import metricsdata = pd.read_csv('creditcard.csv')
scaler=StandardScaler()
data['Amount']=scaler.fit_transform(data[['Amount']])
data = data.drop(['Time'],axis=1)X=data.iloc[:,:-1]
y=data.iloc[:,-1]
train_x,test_x,train_y,test_y=train_test_split(X,y,test_size=0.3,random_state=400)# 过采样操作
from imblearn.over_sampling import SMOTE
oversample=SMOTE(random_state=0)#保证数据拟合效果,随机种子
os_x_train,os_y_train=oversample.fit_resample(train_x,train_y)train_x,test_x,train_y,test_y=train_test_split(os_x_train,os_y_train,test_size=0.3,random_state=400)# 交叉验证
scores=[]
c_param_range=[0.01,0.1,1,10,100]
for i in c_param_range:lr = LogisticRegression(C=i,penalty='l2',solver='lbfgs',max_iter=1000)score = cross_val_score(lr,train_x,train_y,cv=8,scoring='recall')score_mean=sum(score)/len(score)scores.append(score_mean)print(score_mean)
best_c=c_param_range[np.argmax(scores)]
print('best_c=',best_c)lr=LogisticRegression(C=best_c)
lr.fit(train_x,train_y)
predicted=lr.predict(test_x)
print('未调整阈值的报告:'+'\t'+metrics.classification_report(test_y,predicted))# 更改阈值
thresholds=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
recalls=[]
for i in thresholds:global y_predicted_probay_predicted_proba=lr.predict_proba(test_x)y_predicted_proba=pd.DataFrame(y_predicted_proba)y_predicted_proba=y_predicted_proba.drop([0],axis=1)y_predicted_proba[y_predicted_proba[[1]] > i] = 1y_predicted_proba[y_predicted_proba[[1]] <= i] = 0recall=metrics.recall_score(test_y,y_predicted_proba)recalls.append(recall)# print("{} Recall metric in the testing dataset:{:.3f}".format(i,recall))
best_t = thresholds[np.argmax(recalls)]
best_calls = max(recalls)
print("最佳阈值为:{} 对应的recalls为:{:.3f}".format(best_t,best_calls))0.9259697681664929
0.9305118963803862
0.931258151444497
0.9313873112679044
0.9313873112679044
best_c= 10
未调整阈值的报告: precision    recall  f1-score   support0       0.93      0.98      0.96     597571       0.98      0.93      0.95     59652accuracy                           0.95    119409macro avg       0.96      0.95      0.95    119409
weighted avg       0.96      0.95      0.95    119409最佳阈值为:0.1 对应的recalls为:0.988

4.过采样的实验结果

  • 模型召回率显著提升至93%
  • 调整阈值后召回率达到98.8%
http://www.dtcms.com/a/311510.html

相关文章:

  • MQTT 入门教程:MQTT工具调式
  • 堆----2.前 K 个高频元素
  • VirtualBox 的 HOST 键(主机键)是 右Ctrl 键(即键盘右侧的 Ctrl 键)笔记250802
  • 学习笔记:无锁队列的原理以及c++实现
  • Linux 高级 I/O 系统调用详解
  • Vue 响应式基础全解析2
  • Node.js中path模块的使用指南
  • InfluxDB 与 Node.js 框架:Express 集成方案(二)
  • 如何在`<link type=“icon“ href=`的`href`中写SVG并使用path标签? 笔记250802
  • 嵌入式 C 语言入门:递归与变量作用域学习笔记 —— 从概念到内存特性
  • 深入 Go 底层原理(十三):interface 的内部表示与动态派发
  • Javaweb————Apache Tomcat服务器介绍及Windows,Linux,MAC三种系统搭建Apache Tomcat
  • 技术文章:覆铜板的阻燃性
  • UniappDay07
  • 【AI】AIService(基本使用与指令定制)
  • cv快速input
  • 【云计算】云主机的亲和性策略(三):云主机 宿主机
  • Springboot原理和Maven高级
  • 操作系统:远程过程调用( Remote Procedure Call,RPC)
  • MQTT 入门教程:三步从 Docker 部署到 Java 客户端实现
  • Linux基础学习笔记二
  • MySQL PostgreSQL JDBC URL 配置允许批量操作
  • C语言输入安全10大边界漏洞解析与防御
  • 基于LSTM模型与加权链路预测的动态热门商品成长性分析
  • SpringBoot相关注解
  • 项目管理平台是什么?概念、定义、作用、主流厂商解读
  • docker:将python开发的大模型应用,打成docker容器
  • C#中的除法
  • PostGIS面试题及详细答案120道之 (081-090 )
  • cuda编程笔记(12)--学习cuFFT的简单使用