从欠拟合到正则化:用逻辑回归破解信用卡失信检测的召回率困境

在金融风控领域,信用卡信誉检测是一个典型的类别不平衡问题:正常交易样本占绝对多数,而欺诈交易样本极少。我们的核心目标是尽可能多地识别出欺诈交易,这就对模型的召回率(Recall)提出了极高要求。

最近我在做信用卡信誉检测项目时,从模型训练的坑点(欠拟合、过拟合)出发,通过交叉验证和正则化优化,最终有效提升了模型性能,下面就把整个过程分享给大家。

一、问题背景与数据初探

信用卡失信检测数据集(creditcard.csv)包含28个匿名特征、Time(交易时间)、Amount(交易金额)和Class(标签,0为正常交易,1为欺诈交易)。首先,我们观察数据分布:

python 复制代码
import pandas as pd
import matplotlib.pyplot as plt
from pylab import mpl

# 解决中文显示问题
mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei']
mpl.rcParams['axes.unicode_minus'] = False

data = pd.read_csv("creditcard.csv")
labels_count = data['Class'].value_counts()
print(labels_count)

plt.title("正负例样本数")
plt.xlabel("类别")
plt.ylabel("频率")
labels_count.plot(kind='bar')
plt.show()

运行后可以发现,正常交易(0)的数量远多于欺诈交易(1),这是典型的类别不平衡场景。在这种场景下,单纯追求准确率毫无意义------即使模型把所有样本都预测为0,准确率也会极高,但完全无法识别欺诈交易,因此召回率(Recall)才是我们的核心指标。

二、初始模型:从欠拟合到过拟合的困境

首先,我们对数据进行预处理:

• 对Amount特征进行标准化

• 移除无关特征Time

• 划分训练集和测试集(测试集占比30%)然后训练一个基础的逻辑回归模型:

python 复制代码
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
from sklearn.preprocessing import StandardScaler

# 对金额进行标准化
scaler = StandardScaler()
data['Amount'] = scaler.fit_transform(data[['Amount']])
# 移除无关特征
data = data.drop(['Time'], axis=1)

# 分离特征和标签
x = data.drop('Class', axis=1)
y = data['Class']

# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1000)

# 初始化并训练模型
lr = LogisticRegression(C=0.01)
lr.fit(x_train, y_train)

# 模型预测与评估
test_predicted = lr.predict(x_test)
print(metrics.classification_report(y_test, test_predicted))

输出的分类报告显示,模型对欺诈样本(1)的召回率非常低,这意味着大量欺诈交易被漏判,完全无法满足风控需求。

问题分析

  1. 欠拟合:初始模型正则化强度过高(C=0.01),模型过于简单,无法捕捉数据中的规律,导致在训练集和测试集上表现都差。

  2. 过拟合风险:如果我们过度降低正则化强度,模型又会在训练集上表现极好,但在测试集上泛化能力不足,学到了训练数据中的噪声。

  3. 超参数未优化:初始模型使用了默认的正则化强度,可能没有适配数据特性。

  4. 类别不平衡:正常样本过多,模型倾向于预测为多数类,导致少数类召回率低。

三、核心优化:交叉验证+正则化提升召回率

为了解决上述问题,我们引入K折交叉验证来选择最优的正则化惩罚因子,同时使用L2正则化来防止过拟合。

1. 交叉验证选择最优惩罚因子
python 复制代码
from sklearn.model_selection import cross_val_score
import numpy as np

# 定义候选的惩罚因子C
C_range = [0.01, 0.1, 1, 10, 100]
scores = []

# 遍历每个C值,用8折交叉验证计算平均召回率
for i in C_range:
    lr = LogisticRegression(C=i, penalty='l2', solver='lbfgs', max_iter=1000)
    score = cross_val_score(lr, x_train, y_train, cv=8, scoring='recall')
    score_mean = np.mean(score)
    scores.append(score_mean)
    print(f"C={i} 时,平均召回率:{score_mean}")

# 选择召回率最高的C值
best_C = C_range[np.argmax(scores)]
print(f"最优惩罚因子为:{best_C}")

通过交叉验证,我们可以找到在训练集上表现最稳定、召回率最高的正则化强度,避免了单次划分数据带来的偶然性。

2. 用最优参数重建模型
python 复制代码
# 使用最优C值训练最终模型
lr = LogisticRegression(C=best_C, penalty='l2', solver='lbfgs', max_iter=1000)
lr.fit(x_train, y_train)

# 在训练集上评估
train_predicted = lr.predict(x_train)
print("训练集评估报告:")
print(metrics.classification_report(y_train, train_predicted))

# 在测试集上评估
test_predicted = lr.predict(x_test)
print("测试集评估报告:")
print(metrics.classification_report(y_test, test_predicted, digits=6))

同时,我们还可以绘制混淆矩阵来直观地查看模型的预测效果:

python 复制代码
def cm_plot(y, yp):
    from sklearn.metrics import confusion_matrix
    import matplotlib.pyplot as plt
    cm = confusion_matrix(y, yp)
    plt.matshow(cm, cmap=plt.cm.Blues)
    plt.colorbar()
    for x in range(len(cm)):
        for y in range(len(cm)):
            plt.annotate(cm[x,y], xy=(y,x), horizontalalignment='center', verticalalignment='center')
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    return plt

cm_plot(y_test, test_predicted).show()

四、核心知识点:欠拟合、过拟合与正则化

1. 欠拟合与过拟合

• 欠拟合:模型过于简单,在训练集和测试集上表现都差,无法捕捉数据中的规律。

• 过拟合:模型在训练集上表现极好,但在测试集上泛化能力差,学到了训练数据中的噪声和偶然特征。

2. 正则化惩罚

正则化的目的是防止过拟合,通过在损失函数中加入惩罚项,约束模型参数的大小,避免模型过度复杂。

• 原始损失函数(以线性回归为例):

• 加入L2正则化后的损失函数:

其中,就是正则化惩罚项,它会惩罚模型参数的过大值,从而防止过拟合。

3. 交叉验证

交叉验证是一种评估模型性能的方法,它将数据划分为多个子集,轮流用不同子集训练和验证,提升模型评估的可靠性。其中,K折交叉验证是最常用的方法,它将数据划分为K个折叠,每次用K-1个折叠作为训练集,1个折叠作为验证集,最终取K次验证的平均结果作为模型性能的评估。

五、优化效果与关键结论

通过交叉验证和正则化优化,我们得到了显著的效果提升:

  1. 召回率显著提升:欺诈样本的召回率从初始的极低水平提升到了可接受的范围,有效减少了欺诈漏判。

  2. 模型稳定性增强:交叉验证避免了单次数据划分的偶然性,让模型在不同数据子集上的表现更稳定。

  3. 过拟合得到抑制:L2正则化惩罚了模型参数的过大值,提升了模型在测试集上的泛化能力。

六、总结与展望

在信用卡欺诈检测这类类别不平衡的任务中,召回率是比准确率更重要的指标。通过交叉验证选择最优正则化参数,我们可以有效提升模型对少数类的识别能力,同时保证模型的泛化能力。

未来,我们还可以尝试以下方法进一步优化:

• 使用SMOTE等过采样技术处理类别不平衡

• 尝试集成学习方法(如随机森林、XGBoost)

• 调整决策阈值,在精确率和召回率之间做更灵活的权衡

如果你也在处理类似的风控或异常检测问题,不妨试试这些方法,相信会有不错的效果。

相关推荐
im_AMBER2 小时前
Leetcode 111 两数相加
javascript·笔记·学习·算法·leetcode
TracyCoder1232 小时前
LeetCode Hot100(21/100)——234. 回文链表
算法·leetcode·链表
jackywine62 小时前
零样本学习(Zero-Shot Learning)和少样本学习(Few-Shot Learning)有何区别?AI 是怎么“猜“出来的
人工智能·机器学习
可涵不会debug2 小时前
Redis魔法学院——第四课:哈希(Hash)深度解析:Field-Value 层级结构、原子性操作与内部编码优化
数据库·redis·算法·缓存·哈希算法
@––––––2 小时前
力扣hot100—系列1
算法·leetcode·职场和发展
jinyeyiqi20262 小时前
气象监测设备如何助力精细化环境管理?金叶仪器智能气象站方案探讨
人工智能·机器学习·自动驾驶
老鼠只爱大米2 小时前
LeetCode经典算法面试题 #236:二叉树的最近公共祖先(RMQ转化、Tarjan离线算法等五种实现方案详细解析)
算法·leetcode·二叉树·lca·并查集·最近公共祖先·rmq
问好眼2 小时前
【信息学奥赛一本通】1296:开餐馆
c++·算法·动态规划·信息学奥赛
小鸡吃米…2 小时前
机器学习 - 感知机(Perceptron)
人工智能·python·机器学习